如何在执行entityframework.bulkinsert时插入父子?

时间:2015-01-06 16:07:02

标签: entity-framework entity-framework-4 entity-framework-5 entity entity-framework-6

我正在使用Entityframework 6,我试图在数据库中插入父子类数据。 我正在使用Entityframework.BulkInsert来插入数据。我在所有表中都有 autoIncrement int primary key

我的目标如下:

    var parentObjects= new List<parentObject>();            
    var childObjects= new List<childObject>();

        for (int i = 0; i <= 100; i++)
        {
            var parentObj= new parentObject()
            {
                Name="p1",
                Address="a1"
            };

childObjects= SeedInitializer.ChildItems.OrderBy(x => new Random().Next()).Take(2).ToList();//this gets 2 child objects
            foreach (var childObj in childObjects)
            {
                childObj .ParentObject= parentObj;
                //childObj .CommissionPlanId = i;   //tried this still not working
                parentObj.ChildObjects.Add(childObj );                                     
            }
            parentObjects.Add(parentObj);
        }
        //when I do a quickwatch on parentObjects, i see child objects in each parentObject, but                  
        //with the last id of parentObject
        context.BulkInsert(parentObjects, 1000);
        context.SaveChanges();

在保存时,在childObject中创建的只有2条记录是使用错误的parentObject id创建的,即0 在创建父对象时,我无法理解为什么没有创建子项。有人能帮我理解我在做错的地方吗?

2 个答案:

答案 0 :(得分:1)

我认为没有一种简单的方法可以完成此任务,因为为了插入子项,您必须实际插入父项并获取其ID。普通EF插入的优势在于每个INSERT还会嵌入SELECT来获取刚刚生成的标识符,以便它可以用来为子项推送它(如果有的话)。

一种可能的解决方案如下:

  1. Guid RefProperty添加到ParentObject类型,该类型也会保留
  2. Guid BatchId添加到ParentObject类型,该类型也会保留
  3. Guid RefProperty添加到未保留的ChildObject类型
  4. 使用以下(主要是伪代码)序列保存整个结构

    var batchId = new Guid();
    parentObjects.ForEach(item => item.BatchId = batchId);
    
    // set RefProperty for all parents and children to reflect proper parentation 
    
    TransactionScope scope = null;
    try
    {
         context.BulkInsert(parentObjects, 1000);
         var newParents = context.ParentObjects.Where(_ => _.BatchId = batchId);
         var refPropMap = newParents.ToDictionary(_ => _.RefProperty, _ => ParentId);
         var childObjects.ForEach(item => item.ParentId = refPropMap[item.RefProperty]);
         context.BulkInsert(childObjects, 1000);
    
         DataAccess.SaveChanges();
         scope.Complete();
    }
    catch (Exception exc)
    {
         scope?.Dispose();
    }
    
  5. 注意:未经过测试

    这非常难看,但它应该可以解决这个问题:尽量减少到SQL Server的往返行程,但仍然是一个单一的事务。

    为了使SELECT更快,ParentObject表上的索引应放在BatchId上,包括(覆盖)其密钥。

    替代方案:将这些表的设计更改为不使用自动增量,而是使用UNIQUEIDENTIFIER列。这样,可以在进行插入之前设置所有标识符。

答案 1 :(得分:1)

免责声明:我是EntityFramework.BulkInsert

的所有者

你不能。

此功能从未实施过。

免责声明:我是Entity Framework Extensions

的所有者

但是,这个新库(不是免费的)可以轻松处理这种情况。

BulkSaveChanges的工作方式与SaveChanges(处理父/子)完全相同,但速度更快!

支持所有方法:

  • 批量保存更改
  • 批量插入
  • 批量删除
  • 批量更新
  • 批量合并

实施例

// Easy to use
context.BulkSaveChanges();

// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);