简体   繁体   English

C#实体框架批量更新

[英]C# Entity Framework Bulk Update

What is the best way to update multiple records in a list to speed up processing? 更新列表中的多个记录以加快处理速度的最佳方法是什么?

Currently, I'm updating about 15000 products, each with 3 different price sets and it takes the whole day to complete. 目前,我正在更新大约15000种产品,每种产品具有3种不同的价格,并且需要一整天才能完成。

I need to update the prices all at once in code side, then commit those changes to the database in 1 go, instead of fetching each inventory item, updating its values, then attaching it to the context. 我需要在代码端一次更新所有价格,然后将这些更改一次性提交到数据库中,而不是获取每个库存项目,更新其值,然后将其附加到上下文。 Every single fetch is causing the delays. 每次获取都会导致延迟。

Code

public void UpdatePricesFromInventoryList(IList<Domain.Tables.Inventory> invList)
{
    var db = new UniStockContext();

    foreach (var inventory in invList)
    {
        Domain.Tables.Inventory _inventory = db.Inventories
                                            .Where(x => x.InventoryID == inventory.InventoryID)
                                            .FirstOrDefault();

        if (inventory.Cost.HasValue)
            _inventory.Cost = inventory.Cost.Value;
        else
            _inventory.Cost = 0;

        foreach (var inventoryPrices in inventory.AccInventoryPrices)
        {
            foreach (var _inventoryPrices in _inventory.AccInventoryPrices)
            {
                if (_inventoryPrices.AccInventoryPriceID == inventoryPrices.AccInventoryPriceID)
                {
                    _inventoryPrices.ApplyDiscount = inventoryPrices.ApplyDiscount;
                    _inventoryPrices.ApplyMarkup = inventoryPrices.ApplyMarkup;
                    if (inventoryPrices.Price.HasValue)
                        _inventoryPrices.Price = inventoryPrices.Price.Value;
                    else
                        _inventoryPrices.Price = _inventory.Cost;

                    if (inventoryPrices.OldPrice.HasValue)
                    {
                        _inventoryPrices.OldPrice = inventoryPrices.OldPrice;
                    }
                }
            }
        }

        db.Inventories.Attach(_inventory);
        db.Entry(_inventory).State = System.Data.Entity.EntityState.Modified;
    }

    db.SaveChanges();
    db.Dispose();
}

I've also tried working my code according to this SOQ Entity Framework update/insert multiple entities and it gave me and error. 我还尝试根据此SOQ 实体框架更新/插入多个实体来工作我的代码,这给了我错误。 Here are the details: 详细信息如下:

Code: 码:

    public void UpdatePricesFromInventoryListBulk(IList<Domain.Tables.Inventory> invList)
    {
        var accounts = new List<Domain.Tables.Inventory>();
        var db = new UniStockContext();
        db.Configuration.AutoDetectChangesEnabled = false;

        foreach (var inventory in invList)
        {
            accounts.Add(inventory);
            if (accounts.Count % 1000 == 0)
            {
                db.Set<Domain.Tables.Inventory>().AddRange(accounts);
                accounts = new List<Domain.Tables.Inventory>();
                db.ChangeTracker.DetectChanges();
                db.SaveChanges();
                db.Dispose();
                db = new UniStockContext();
            }
        }

        db.Set<Domain.Tables.Inventory>().AddRange(accounts);
        db.ChangeTracker.DetectChanges();
        db.SaveChanges();
        db.Dispose();
    }

Error: 错误:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

I would suggest changing the following: 我建议更改以下内容:

    Domain.Tables.Inventory _inventory = db.Inventories
                                    .Where(x => x.InventoryID == inventory.InventoryID)
                                    .FirstOrDefault();

To

Domain.Tables.Inventory _inventory = db.Inventories
                                    .Single(x => x.InventoryID == inventory.InventoryID);

I'd still add the db.Configuration.AutoDetectChangesEnabled = false; 我仍然会添加db.Configuration.AutoDetectChangesEnabled = false; after getting the context, and also use AsNoTracking: Turn off EF change tracking for any instance of the context 获取上下文后,还可以使用AsNoTracking: 对上下文的任何实例关闭EF更改跟踪

that is because you are hit the database context at every loop to increase the performance you should get all the Inventories by one hit ,this is your problem try the below code and you will notice the performance : 那是因为您在每个循环中都命中数据库上下文以提高性能,因此您应该一键获得所有清单,这是您的问题,请尝试以下代码,您将注意到性能:

    public void UpdatePricesFromInventoryList(IList<Domain.Tables.Inventory> invList)
{
    var db = new UniStockContext();
    invIdsArray = invList.select(x => x.InventoryID).ToArray();
    IList<Domain.Tables.Inventory>  invListFromDbByOneHit = db.Inventories.Where(x => invIdsArray.Contains(x.InventoryID)).Tolist();
    foreach (var inventory in invListFromDbByOneHit)
    {
        //Domain.Tables.Inventory _inventory = db.Inventories
                                            //.Where(x => x.InventoryID == inventory.InventoryID)
                                            //.FirstOrDefault();

        if (inventory.Cost.HasValue)
            _inventory.Cost = inventory.Cost.Value;
        else
            _inventory.Cost = 0;

        foreach (var inventoryPrices in inventory.AccInventoryPrices)
        {
            foreach (var _inventoryPrices in _inventory.AccInventoryPrices)
            {
                if (_inventoryPrices.AccInventoryPriceID == inventoryPrices.AccInventoryPriceID)
                {
                    _inventoryPrices.ApplyDiscount = inventoryPrices.ApplyDiscount;
                    _inventoryPrices.ApplyMarkup = inventoryPrices.ApplyMarkup;
                    if (inventoryPrices.Price.HasValue)
                        _inventoryPrices.Price = inventoryPrices.Price.Value;
                    else
                        _inventoryPrices.Price = _inventory.Cost;

                    if (inventoryPrices.OldPrice.HasValue)
                    {
                        _inventoryPrices.OldPrice = inventoryPrices.OldPrice;
                    }
                }
            }
        }

        db.Inventories.Attach(_inventory);
        db.Entry(_inventory).State = System.Data.Entity.EntityState.Modified;
    }

    db.SaveChanges();
    db.Dispose();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM