0

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()
5
  • 1
    multiple calls to db.Add and then finally calling the async version of the SaveChanges is just enough to do async db updates. so, your sample code above is just fine. Commented Jul 19, 2022 at 3:18
  • 2
    But adding and using await will result in the code waiting, so it's certainly not going to be more responsive from the user and UI point of view.so you gain nothing in terms of performance here, nor see a change in UI speed either Commented Jul 19, 2022 at 3:22
  • 1
    But, if you don't mind doing it fire and forget style, you don't actually need to await the results of your ` SaveAsync` call. And, to be nit-picking, awaiting a task does not really "result in your code waiting" Commented Jul 19, 2022 at 3:27
  • Thank you for the answers. @AlbertD.Kallal Once the duplication is complete, the response will trigger a re render of the table listing all the items in the DB on the front end. Am I correct in assuming that waiting for the changes to complete before sending the OK response would be a better practice. Commented Jul 19, 2022 at 3:27
  • But don't wait, await. There's a big difference Commented Jul 19, 2022 at 3:30

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the AsNoTracking() . That is specifically super helpful. Much appreciated!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.