2016-04-06 14 views
2

NPoco(PetaPoco由来する.NETマイクロORM)で知られているTは、ジェネリック型のリストが与えられると、データベースに一括挿入レコードのための方法を有しています。メソッドシグネチャは次のとおりはInsertBulk <T>(IEnumerableを<T> POCOS)を呼び出す必要があるだけランタイム

void InsertBulk<T>(IEnumerable<T> pocos); 

は、内部的には、型Tの名前をとり、(同様に型のプロパティ名は、列名にマップされている)に挿入するDBテーブルを決定するためにそれを使用します。 したがって、正しい型の変数がメソッドに渡されることが非常に重要です。

私の挑戦はこれです:私はIDataItemがすべて挿入可能なオブジェクトのクラスは

  • を実装する必要があり、リストに含めることのできるインターフェイスであるList<IDataItem>として、DBに挿入するオブジェクトのリストを与えられています

    • IDataItemを実装する任意の型のオブジェクト、および問題を強調するために、リスト
    • に種類の混合物があるかもしれません - 私は、コンパイル時に私はInsertBulk
    • に渡す必要があり、実際の具体的な種類を知りません

    私は以下のアプローチを試みましたが、Convert.ChangeTypeの結果はObjectです。したがって、オブジェクトのリストをInsertBulkに渡していますが無効です。

    private static Exception SaveDataItemsToDatabase(List<IDataItem> dtos) 
        { 
         using (var db = new DbConnection()) 
         { 
          try 
          { 
           var dtosByType = dtos.GroupBy(x => x.GetType()); 
    
           db.Data.BeginTransaction(); 
    
           foreach (var dataType in dtosByType) 
           { 
            var type = dataType.Key; 
            var dtosOfType = dataType.Select(x => Convert.ChangeType(x, type)); 
    
            db.Data.InsertBulk(dtosOfType); 
           } 
    
           db.Data.CommitTransaction(); 
    
           return null; 
          } 
          catch (Exception ex) 
          { 
           db.Data.RollbackTransaction(); 
    
           return ex; 
          } 
         } 
        } 
    

    私はこれを達成する方法はありますか?

  • +0

    あなたは 'dynamic'キーワードを使用してみましたが? –

    +0

    dtosOfTypeを動的として宣言すると、同じ結果が得られます。BulkInsertに渡される変数はObjectのリストです。 – Laurence

    +0

    Reflectionを試しましたか? 'Type.GetMethod()'を使ってメソッド定義を取得し、 'MethodInfo.Invoke()'をそれぞれの 'System.Type'sで使用しますか? – Adwaenyth

    答えて

    3

    List<T>の新しいリストを作成して、すべてのアイテムをコピーしてから、InsertBulkにリフレクションで電話する必要があります。

    foreach(var g in groups) 
    { 
    
        var dataItemType = g.Key; 
        var listType = typeof(List<>).MakeGenericType(new [] { dataItemType }); 
        var list = (IList) Activator.CreateInstance(listType); 
    
        foreach(var data in g) 
         list.Add(data); 
    
        db.Data.GetType() 
          .GetMethod("InsertBulk") 
          .MakeGenericMethod(dataItemType) 
          .Invoke(db.Data, new object[] { list }); 
    
    } 
    

    それはここで働いてください:https://dotnetfiddle.net/BS2FLy

    +0

    この行でexを取得する: 'System.Collections.Generic.List'1 [TestConsole.Program + IDataItem]'型のオブジェクトを 'System.Collections.Generic.IEnumerable'1 [Program + Test1Dto]'に変換することはできません。 – Laurence

    +0

    @Laurenceはそれを修正しました、間違いなく今働きます。 – dcastro

    +0

    はいそれは動作します!ありがとうございました - 私は不可能な問題にぶつかったと思いました! – Laurence

    1

    このコードは、あなたが(少しハックが)やりたいあなたを助けるかもしれません。私は上の推測を取るつもりです

    private static Exception SaveDataItemsToDatabase(List<IDataItem> dtos) 
        { 
         using (var db = new DbConnection()) 
         { 
          try 
          { 
           var dtosByType = dtos.GroupBy(x => x.GetType()); 
    
           db.Data.BeginTransaction(); 
           var method = db.Data.GetType().GetMethod("InsertBulk"); 
           foreach (var dataType in dtosByType) 
           { 
            var genericMethod = method.MakeGenericMethod(dataType.Key); 
            genericMethod.Invoke(db.Data, new object[] { dataType.Value };     
           } 
    
           db.Data.CommitTransaction(); 
    
           return null; 
          } 
          catch (Exception ex) 
          { 
           db.Data.RollbackTransaction(); 
    
           return ex; 
          } 
         } 
        } 
    
    +0

    これは基本的にdcastroと同じ答えです。 –

    +0

    私がそれを書いていたとき、彼の答えは削除されました。プラス、彼の答えは実際には動作しません - 彼は正しいタイプに配列をキャストする必要があります。 – Evk

    +0

    これも動作します... dcastroと非常によく似ていますが、彼はこれの前に数分を投稿しました。とにかくありがとう。 – Laurence

    1

    :あなたの元のコードを使用している場合、それはのようなものになります

    class Program { 
        static void Main() { 
         var items = new IDataItem[] { 
          new TestItem(), 
          new TestItem(), 
          new TestItem2(), 
          new TestItem2(), 
         }; 
    
         foreach (var kv in items.GroupBy(c => c.GetType())) { 
          // group by actual type 
          var type = kv.Key; 
          var batch = kv.ToArray(); 
          // grab BulkInsert<Type> method 
          var insert = typeof(Test).GetMethod("BulkInsert").MakeGenericMethod(type); 
          // create array of Type[] 
          var casted = Array.CreateInstance(type, batch.Length); 
          Array.Copy(batch, casted, batch.Length); 
          // invoke 
          insert.Invoke(new Test(), new object[] { casted}); 
         }    
    
         Console.ReadKey(); 
        }   
    } 
    
    public interface IDataItem { 
    
    } 
    
    public class TestItem : IDataItem { 
    
    } 
    
    public class TestItem2 : IDataItem 
    { 
    
    } 
    
    public class Test { 
        public void BulkInsert<T>(IEnumerable<T> items) { 
         Console.WriteLine(typeof(T).Name); 
        } 
    } 
    

    これは私の側でそれを実行するコードを持っていないからです。

    方法について:

    private static Exception SaveDataItemsToDatabase(List<IDataItem> dtos) 
    { 
        using (var db = new DbConnection()) 
        { 
         try 
         { 
    
          db.Data.BeginTransaction(); 
    
          dtos 
           .GroupBy(dto => dto.GetType()) 
           .ForEach(grp => { 
            db.Data.BulkInsert(dtos.Where(n => n.GetType().Equals(grp.Key).ToList()); 
           }); 
    
          db.Data.CommitTransaction(); 
    
          return null; 
         } 
         catch (Exception ex) 
         { 
          db.Data.RollbackTransaction(); 
    
          return ex; 
         } 
        } 
    } 
    
    +0

    Invokeが呼び出されたときにこの例外が発生します。 'System.Collections.Generic.List'1のオブジェクト[TestConsole.Program + IDataItem]'を型 'System.Collections.Genericに変換できません。 IEnumerable'1 [TestConsole.Program + Test1Dto] '。 – Laurence

    +0

    Test1DtoはIDataItemを実装する私の型の1つです – Laurence

    +0

    @Laurenceこのエラーを避けるために私の答えを見てください – Evk

    0

    :あなたはこのような何かを試みることができる

    private static Exception SaveDataItemsToDatabase(List<IDataItem> dtos) 
        { 
         using (var db = new DbConnection()) 
         { 
          try 
          {      
           db.Data.BeginTransaction(); 
           foreach (var dataType in dtos.GroupBy(x => x.GetType())) { 
            var type = dataType.Key; 
            var items = dataType.ToArray(); 
            var insert = db.Data.GetType().GetMethod("BulkInsert").MakeGenericMethod(type); 
            // create array of Type[] 
            var casted = Array.CreateInstance(type, items.Length); 
            Array.Copy(items, casted, items.Length); 
            // invoke 
            insert.Invoke(db.Data, new object[] {casted}); 
           } 
    
           db.Data.CommitTransaction(); 
    
           return null; 
          } 
          catch (Exception ex) 
          { 
           db.Data.RollbackTransaction(); 
    
           return ex; 
          } 
         } 
        } 
    
    +0

    前と同じ種類のエラーを取得しています( "宛先テーブル 'IDataItem'にアクセスできません。 IDataItemのList型の変数でBulkInsertが呼び出されたためです。 – Laurence

    関連する問題