简体   繁体   English

使用 EntityFramework 6 和 Linq 批量更新对象列表

[英]Batch update on object list using EntityFramework 6 and Linq

I want to create a function that accepts a list of objects with their properties already set and does a batch update or insert on them only making 1 call to the database.我想创建一个函数,该函数接受已设置其属性的对象列表,并对它们进行批量更新或插入,仅对数据库进行 1 次调用。

(UPDATE) Here is the working version: (更新)这是工作版本:

    public static void BatchInsertProducts(IList<Product> productList)
    {
        using (var context = new DbContext())
        {
            context.Products.AddRange(productList);
            context.SaveChanges();
        }
    }

This is my attempt at doing either and update or an insert on several items based on the Id.这是我尝试根据 Id 对多个项目进行更新或插入的尝试。 I don't think I can use AddRange here so I tried it this way and I am getting an error:我不认为我可以在这里使用 AddRange,所以我以这种方式尝试,但出现错误:

    public static void SaveMultipleProducts(IList<Product> productList)
    {
        using (var context = new DbContext())
        {
            foreach (Account p in productList)
            {
                if (p.ID == 0)
                {
                    context.Entry(p).State = EntityState.Added;
                    p.InsertUserId = "jtunney";
                    p.InsertDate = DateTime.Now;
                }
                else
                {
                    context.Entry(p).State = EntityState.Modified;
                    p.UpdateUserId = "jtunney";
                    p.UpdateDate = DateTime.Now;
                }
            }
            context.SaveChanges();
        }
    }

Removed foreach loop, changed IList<Product> to IEnumerable<Product> :删除了 foreach 循环,将IList<Product>更改为IEnumerable<Product>

public static void BatchInsertProducts(IEnumerable<Product> productList)
{
    using (var context = new DbContext())
    {
        context.Products.AddRange(productList);
        context.SaveChanges();
    }
}

One way to do save multiple:保存多个的一种方法:

public static void SaveMultipleProducts(IEnumerable<Product> productList)
{
    using (var context = new DbContext())
    {
        foreach (Account p in productList)
        {
            p.InsertUserId="jtunney";
            p.InsertDate=DateTime.Now;
            context.Entry(p).State=p.Id==0?EntityState.Added:EntityState.Modified;
        }
        context.SaveChanges();
    }
}

Another way:其它的办法:

public static void SaveMultipleProducts(IList<Product> productList)
{
    using (var context = new DbContext())
    {
        foreach (Account p in productList)
        {
            p.InsertUserId="jtunney";
            p.InsertDate=DateTime.Now;
        }
        // Add all records
        context.Products.AddRange(productList);

        // Handle updates
        foreach(var p in productList.Where(p=>p.id!=0))
        {
          context.Entry(p).State=EntityState.Modified;
        }
        context.SaveChanges();
    }
}

It's not necessary to call Save method for each product.没有必要为每个产品调用 Save 方法。 If you get the products and save with the same DbContext you only have to call Save one time, then It will save all your modifications.如果您获得产品并使用相同的 DbContext 保存,则只需调用 Save 一次,它将保存您的所有修改。

Imagine想象

List<Product> products = Context.Product.ToList();

foreach(var product in products)
{
     product.Price = new Random().Next();
}

Context.Product.SaveChanges();

This code is modifying the price for all Products in the list, but thanks to the fact that we are using the same context to retrieve the results and that EF implements Tracking to save the modifications with one call to SaveChanges it's enough.此代码正在修改列表中所有产品的价格,但由于我们使用相同的上下文来检索结果,并且EF 实现了跟踪以通过一次调用 SaveChanges 来保存修改,这已经足够了。

For bulkInserts对于批量插入

Use AddRange method from Entity Framework http://www.entityframeworktutorial.net/EntityFramework6/addrange-removerange.aspx or you can try this library https://efbulkinsert.codeplex.com/ .使用 Entity Framework http://www.entityframeworktutorial.net/EntityFramework6/addrange-removerange.aspx 中的AddRange 方法,或者您可以尝试这个库https://efbulkinsert.codeplex.com/ I have heard about it, but I have never used it听说过,但没用过

This is bit different approach than other....这与其他方法有点不同......

public static DbContext BatchInsertProducts(DbContext context,IList<Product> productList)
{
    context.Configuration.AutoDetectChangesEnabled = false;
    for (int i = 0; i < lobbies.Count; i += 100)
    {
        context.Set<Product>().AddRange(lobbies.GetRange(i, Math.Min(100, lobbies.Count - i)));
        context.Products.AddRange(productList);
        context.SaveChanges();

        //Dispose and create a context
        context.Dispose();
        context = new DbContext;
        context.Configuration.AutoDetectChangesEnabled = false;   
    }

    return context;
}

The above mentioned code snippet does some additional task inorder to improve the performance and also we can specify the number of records that need to included in each batch manipulation.上面提到的代码片段做了一些额外的任务以提高性能,我们还可以指定需要包含在每个批处理操作中的记录数

If we want to insert bulk records, creating new context for each batch and dispose then once task is done.如果我们想插入批量记录,为每个批次创建新的上下文并在任务完成后进行处理。 very much improve the performance (from minutes to operation to seconds)极大地提高了性能(从几分钟到操作到几秒钟)

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

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