NPoco(.NET微型ORM,派生自PetaPoco)有一种方法,可以在给定通用类型列表的情况下将记录批量插入数据库。方法签名是:
void InsertBulk<T>(IEnumerable<T> pocos);
在内部,它采用类型T的名称并使用它来确定要插入的数据库表(类似地,类型的属性名称映射到列名称)。 因此,将正确类型的变量传递给方法至关重要。
我的挑战是:
List<IDataItem>
,其中IDataItem是所有可插入对象的类必须实现的接口我尝试了以下方法,但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 :(得分: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 });
}
答案 1 :(得分:1)
这段代码可能会帮助你做你想做的事情(虽然有点hacky)。
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;
}
}
}
答案 2 :(得分: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;
}
}
}
答案 3 :(得分: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;
}
}
}