LoginSignup
9
7

More than 5 years have passed since last update.

PetaPoco使いやすいよ。

Last updated at Posted at 2015-10-31

PetaPoco
http://www.toptensoftware.com/petapoco/
https://github.com/toptensoftware/PetaPoco

いわゆるマイクロO/Rマッパーです。
最新はバージョン5です。
メンテナンスは継続して続いています。

以下の点が便利でよく使ってます。

  • クラス群が1ファイルで完結している。dll配布でない。
  • T4テンプレートでPocoクラスが作成できる。
  • 作成されたPocoクラスはSelect Update Insert Deleteがそろってる。
  • Page SingleOrDefaultがある。
  • 遅くない。

Dapperをベースに周辺群を自作されている方が多いのだと思いますが
私はメンドクサイのでPetaPocoが好きです。

で使っていると少しずつ変更とか追加したりすることがあったりするのでまとめときます。

パラメータクエリの引数にDictionaryを使いたい。

なんてことがあります。
PetaPocoにはPetaPoco.sqlというクラスがあって小さいクエリビルダーを提供しています。
こんなかんじ

            var sql = PetaPoco.Sql.Builder
                .Select("HG.*")
                .From("HOGE HG");
                .Where("HG.id = @0", 5)
                .Where("HG.name = @Name" new { Name = "hogehoge" } );

パラメーラクエリは一つずつ指定する方法にも対応しているし匿名型にてマップする方法にも対応しています。
もちろん匿名型はあんまり速くはないですけど便利です。

ただ、この二つだとうまくいかないなぁって場面があることがあって
IN句うまく表現できないんですよね。
でDictionaryに対応させることでIN句を表現できると考えて対応させました。


public class ParamDictionary : Dictionary<string, object> {
        public ParamDictionary()
        {

        }
        public ParamDictionary(IDictionary<string, object> dictionary) : base(dictionary)
        {

        }
    }

とりあえずPetaPoco名前空間にこんなの追加しておいて
PetaPoco.Internal.ParametersHelper のProcessParamsメソッドの
args_srcをforeachしてる部分を

                        foreach (var o in args_src)
                        {
                            // Custom Start
                            if(o.GetType() == typeof(ParamDictionary))
                            {
                                var dic = (ParamDictionary)o;
                                if(dic.ContainsKey(param))
                                {
                                    arg_val = dic[param];
                                    found = true;
                                    break;
                                }
                            }
                            // Custom End

                            var pi = o.GetType().GetProperty(param);
                            if (pi != null)
                            {
                                arg_val = pi.GetValue(o, null);
                                found = true;
                                break;
                            }
                        }

こんな風にしておくどDictionaryに対応できます。
でどう使うかというと

            var hoges = new List<string> { "hoge1", "hage2", "hige3" };
            var dichoges = (ParamDictionary)hoges.Select((x, i) => new { Key = "Names" + i, Value = (object)x }).ToDictionary(x => x.Key, x => x.Value);
            sql.Where("Name IN (" + String.Join(" ,", dichoges.Select(x => "@" + x.Key)) + " )", dichoges);

もうちょっとやりようがある気もしますが・・・(;・∀・)

プロシージャコールでアウトパラメータ受け取りたい。

私の開発では殆どがOracleかSQLServerなのですがプロシージャコールでOutPutパラメータを使いたい時とかがあります。
PetaPocoでは基本的にOutputパラメータを扱えないです。
outパラメータが存在しないDBがあるからだと思います。
ですのでこんな関数を作りました。


        public T ExcuteProcedure<T>(string ProcedureName, ParamDictionary in_args, ParamDictionary out_args)
        {
            try
            {
                OpenSharedConnection();
                try
                {
                    using(var cmd = Connection.CreateCommand())
                    {
                        cmd.Connection = Connection;
                        cmd.CommandText = ProcedureName;
                        cmd.Transaction = _transaction;
                        cmd.CommandType = CommandType.StoredProcedure;
                        if (in_args != null)
                        {
                            foreach (var item in in_args)
                            {
                                var idbParam = item.Value as IDbDataParameter;
                                if (idbParam != null)
                                {
                                    idbParam.ParameterName = string.Format("{0}{1}", _paramPrefix, item.Key);
                                    cmd.Parameters.Add(idbParam);
                                    continue;
                                }

                                var p = GetProcParam(string.Format("{0}{1}", _paramPrefix, item.Key), item.Value, ParameterDirection.Input);
                                cmd.Parameters.Add(p);
                            }
                        }
                        if(out_args != null)
                        {
                            foreach (var item in out_args)
                            {
                                var idbParam = item.Value as IDbDataParameter;
                                if (idbParam != null)
                                {
                                    idbParam.ParameterName = string.Format("{0}{1}", _paramPrefix, item.Key);
                                    cmd.Parameters.Add(idbParam);
                                    continue;
                                }

                                var p = GetProcParam(string.Format("{0}{1}", _paramPrefix, item.Key), item.Value, ParameterDirection.Output);
                                cmd.Parameters.Add(p);
                            }
                        }

                        var returnvalue = cmd.CreateParameter();
                        returnvalue.ParameterName = "returnVal";
                        returnvalue.Direction = ParameterDirection.ReturnValue;
                        cmd.Parameters.Add(returnvalue);

                        _dbType.PreExecute(cmd);
                        DoPreExecute(cmd);

                        var retv = cmd.ExecuteNonQuery();
                        OnExecutedCommand(cmd);

                        foreach(IDataParameter param in cmd.Parameters)
                        {
                            if(param.Direction == ParameterDirection.Output)
                            {
                                var beforekey = param.ParameterName.Replace(_paramPrefix, "");
                                if(out_args.ContainsKey(beforekey))
                                {
                                    out_args[beforekey] = param.Value;
                                }                                
                            }
                        }

                        object val = returnvalue.Value;

                        Type u = Nullable.GetUnderlyingType(typeof(T));
                        if (u != null && val == null)
                            return default(T);

                        return (T)Convert.ChangeType(val, u == null ? typeof(T) : u);                       
                    }
                }
                finally
                {
                    CloseSharedConnection();
                }
            }
            catch (Exception x)
            {
                if (OnException(x))
                    throw;
                return default(T);
            }
        }

そのまんまです。
でも暗黙カーソルとかには対応いていないです。

他にもちょこちょこ直したり追加したりしながら使ってます。

あんまり日本語情報ないので使っている人少ないのかなぁとは思いますが
悪くはないライブラリだと思いますので、なんかあったときはお試しでどうぞ。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7