Let's assume that I have a list of database entries and I want to duplicate them in the database. Would a regular foreach
and db.Add()
work, or is there an asynchronous way I should be using with db.Add()
?
PS: this is not the actual code, just an example of what I'm trying to accomplish
var pencils = await db.Pencils.Where(x => x.IsBroken == false).ToListAsync();
foreach (var pencil in pencils)
{
pencil.ID = 0;
db.Add(pencil)
}
await db.SaveChangesAsync()
CodePudding user response:
If your intention is to duplicate the broken pencils, your code is slightly flawed. You are loading tracked entities, and I'd be assuming that by setting the ID to 0 you'd want to insert new rows where an identity would take over assigning new IDs. EF entities will chuck an exception if you try setting a tracked entity's PK.
Instead:
var pencils = await db.Pencils.AsNoTracking()
.Where(x => x.IsBroken == false)
.ToListAsync();
db.AddRange(pencils);
await db.SaveChangesAsync()
AsNoTracking
ensures the DbContext does not track the entities loaded. This means if we use Add
, or in this case AddRange
to add them all at once, provided those entities are declared with an Identity-based PK (Pencil.Id) then EF treats them as new entities and they would be assigned a new PK by the underlying database when saved.
As mentioned in the comments, "awaiting" an operation does not wait for the operation. That would be more along the lines of doing:
db.SaveChangesAsync().Wait();
... which would block the current thread until the SaveChanges
completed.
await
marks a continuation point so that the caller of the encompassing async
operation can continue and a resumption point will be picked up and executed at some point after the operation is completed. So for instance in a web action handler, the thread that ASP.Net Core or IIS allocated to action the request can be free to pick up and start processing a new request while this runs in the background. The request will get it's response populated and sent back after completion.