Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any difference between calling SaveChanges() inside and outside a foreach loop?

Is there any performance benefit/technical differences between calling EF SaveChanges() in a foreach loop or outside a loop, assuming a change is made to an EF entity inside the loop?

like image 385
jaffa Avatar asked Jun 21 '12 08:06

jaffa


People also ask

What does the Dbcontext SaveChanges () method return?

Returns. The number of state entries written to the underlying database. This can include state entries for entities and/or relationships.

When should I call SaveChangesAsync?

But fundamentally, an async call is about much more than that. The idea here is that if there is other work you can do (on the server) while the Save operation is in progress, then you should use SaveChangesAsync .

Does SaveChanges commit?

In Entity Framework, the SaveChanges() method internally creates a transaction and wraps all INSERT, UPDATE and DELETE operations under it. Multiple SaveChanges() calls, create separate transactions, perform CRUD operations and then commit each transaction.

What is the return type of SaveChanges in Entity Framework?

SaveChanges() always returns 0 – Entity Framework According to EF documentation, SaveChanges() should return a number of affected rows.


2 Answers

YES!

If you call it inside the loop, EF will write back the changes to the database for every single entity (and every entity will be in its own, separate transaction).

The other way around, you'll make all your changes and EF will write them back all at once after the loop (in one single transaction for all entities together).

As a general rule of thumb (without actually seeing your code) try to have as few calls to .SaveChanges() as possible.

One call with 50 changes is typically much better / faster / more efficient than 50 calls for 1 change each.

like image 200
marc_s Avatar answered Sep 21 '22 04:09

marc_s


One other remark to make is that suppose your foreach loops over an EntitySet that is active in your DbContext you'll get a System.Data.SqlClient.SqlException: another thread is running in the session.

This is because the foreach actually runs in another thread and this is not allowed for the transaction to complete.

This besides the remarks made above that fewer transactions are better.

Suppose you have a context db and do the following:

var groups = from i in db.items select i.GroupNumber;
foreach( var grp in groups)
{
    //... do something
    db.SaveChanges();
}

This will throw the exception

A solution to avoid this (if appropriate!!) is to 'materialize' the groups entityset by bringing them into Object space by changing the first line into:

var groups = (from i in db.items select i.GroupNumber).ToList();

This will allow you to save in the foreach (if needed)

like image 36
Tom Avatar answered Sep 20 '22 04:09

Tom