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?
Returns. The number of state entries written to the underlying database. This can include state entries for entities and/or relationships.
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 .
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.
SaveChanges() always returns 0 – Entity Framework According to EF documentation, SaveChanges() should return a number of affected rows.
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With