简体   繁体   中英

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.

(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. I don't think I can use AddRange here so I tried it this way and I am getting an error:

    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> :

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. 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.

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.

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/ . 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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