2

NPoco (PetaPoco から派生した .NET マイクロ ORM) には、ジェネリック型のリストを指定して、レコードをデータベースに一括挿入する方法があります。メソッドのシグネチャは次のとおりです。

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

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

私の課題はこれです:

  • List<IDataItem>IDataItem はすべての挿入可能なオブジェクトのクラスが実装する必要があるインターフェイスであるため、DB に挿入するオブジェクトのリストが与えられます。
  • リストには、IDataItem を実装する任意のタイプのオブジェクトを含めることができ、リストにはタイプが混在している可能性があります。
  • 問題を強調するために - InsertBulk に渡さなければならない実際の具象型をコンパイル時に知りません

私は次のアプローチを試みましたが、Convert.ChangeType の結果はオブジェクトであるため、オブジェクトのリストを 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;
            }
        }
    }

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

4

4 に答える 4

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();
                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;
            }
        }
    }
于 2016-04-06T15:07:55.323 に答える
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;
            }
        }
    }
于 2016-04-06T15:11:10.497 に答える
0

私の側で実行するためのコードがないため、これについては知識に基づいた推測を行います。

どうですか:

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;
        }
    }
}
于 2016-04-06T15:13:50.197 に答える