代码之家  ›  专栏  ›  技术社区  ›  Orion

C实体框架批量更新

  •  1
  • Orion  · 技术社区  · 8 年前

    更新列表中的多条记录以加快处理速度的最佳方法是什么?

    目前,我正在更新大约15000种产品,每种都有3种不同的价格,需要一整天才能完成。

    我需要在代码端一次更新所有价格,然后在1go中将这些更改提交到数据库,而不是获取每个库存项,更新其值,然后将其附加到上下文。每一次提取都会导致延迟。

    代码

    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();
    }
    

    我也试过根据这个SOQ来处理我的代码 Entity Framework update/insert multiple entities 它给了我错误。详情如下:

    代码:

        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();
        }
    

    错误:

    An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   user5292841    8 年前

    我建议更改以下内容:

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

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

    在获取上下文之后,我仍然会添加db.configuration.autodetectchangesenabled=false;并使用asnotracking: Turn off EF change tracking for any instance of the context

        2
  •  -1
  •   Eng Hazymeh    8 年前

    这是因为您在每个循环中都会碰到数据库上下文以提高性能—您应该一次性获得所有清单,这是您的问题—请尝试下面的代码,您会注意到性能:

        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();
    }