C
C#3mo ago
Core

✅ EF SaveChanges in transactions

Hello, Does it make a difference if SaveChanges is called after each Add operation or only one time after the last Add operation? Multiple times
c#
await using var transaction = await _dbContext.Database.BeginTransactionAsync();

await _dbContext.Domains.AddAsync(domain);
await _dbContext.SaveChangesAsync();

await _dbContext.DomainVerifications.AddAsync(domainVerification);
await _dbContext.SaveChangesAsync();

await transaction.CommitAsync();
c#
await using var transaction = await _dbContext.Database.BeginTransactionAsync();

await _dbContext.Domains.AddAsync(domain);
await _dbContext.SaveChangesAsync();

await _dbContext.DomainVerifications.AddAsync(domainVerification);
await _dbContext.SaveChangesAsync();

await transaction.CommitAsync();
One time
c#
await using var transaction = await _dbContext.Database.BeginTransactionAsync();

await _dbContext.Domains.AddAsync(domain);
await _dbContext.DomainVerifications.AddAsync(domainVerification);

await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
c#
await using var transaction = await _dbContext.Database.BeginTransactionAsync();

await _dbContext.Domains.AddAsync(domain);
await _dbContext.DomainVerifications.AddAsync(domainVerification);

await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
17 Replies
jcotton42
jcotton423mo ago
In terms of data consistency, no. In terms of db round trips, yes. Also, don’t use AddAsync. It’s only used for specific scenarios like hi-lo ID generation.
Core
CoreOP3mo ago
Thank you I thought we should always use the Async operations I have columns like CreatedAt and Id generated on DB side when an entity is added
jcotton42
jcotton423mo ago
That’s done at save time. Add just adds to the change tracker, it does not round trip to the database.
Core
CoreOP3mo ago
Okay, is this only with the Add or are there other methods where the non async version should be used over the async?
jcotton42
jcotton423mo ago
Stack Overflow
What's the Hi/Lo algorithm?
What's the Hi/Lo algorithm? I've found this in the NHibernate documentation (it's one method to generate unique keys, section 5.1.4.2), but I haven't found a good explanation of how it works. I k...
jcotton42
jcotton423mo ago
Anything that just touches the change tracker. So pretty much just Add and Remove. (There’s other change tracker methods like Update and Attach, but most of the time if you’re using those you need to rethink your approach) Actually, I don’t think RemoveAsync is even a thing.
Core
CoreOP3mo ago
I am using the Attach method when I don't query the user from the database for a navigation property. For example, I extract the UserId from the access token, and do the following:
c#
var user = new User {Id = GetUserIdFromToken()};
_dbContext.attach(user);
unsavedEntity.User = user;
await _dbContext.Entities.AddAsync(unsavedEntity);
c#
var user = new User {Id = GetUserIdFromToken()};
_dbContext.attach(user);
unsavedEntity.User = user;
await _dbContext.Entities.AddAsync(unsavedEntity);
Should the AddAsync remain, whenever Attach was used beforehand?
jcotton42
jcotton423mo ago
No. Also, rather than doing that, just add a UserId prop to the class for unsavedEntity. Again, AddAsync only makes a difference for very specific ID generation setups. In all other cases, you are paying the overhead of an async state machine for no reason.
Core
CoreOP3mo ago
I remember getting an error because the User was not tracked, but I will try that again Thank you for helping me
jcotton42
jcotton423mo ago
No, you wouldn’t make a User here at all. Instead you’d do unsavedEntity.UserId = id;
The Fog from Human Resources
I always use it :SCfeet: What should I use instead
Core
CoreOP3mo ago
I am using shadow properties, that means I only have a navigation property User, and not UserId. If I do the following: unsavedEntity.User = new User {Id = id} and try to save it, I will get the following error: duplicate key value violates unique constraint "pk_users". I think this is because EF tries to insert the user in the database. When I attach the user object to the context it lets me save the unsavedEntity
jcotton42
jcotton423mo ago
Add, unless you’re doing HiLo ID.s. And that’s something you have to set up explicitly. Add UserId to your model, that’s what I’m saying.
The Fog from Human Resources
So i basically gain nothing from AddAsync that Add can't provide?
jcotton42
jcotton423mo ago
You can have both, EF works with it just fine. Not only do you gain nothing, you end up paying the overhead of an async call. Unless you’re doing HiLo, there’s no database roundtrip involved. Nothing actually goes to the database until SaveChanges.
The Fog from Human Resources
:SCshocked: Interesting I love EF Core. :SChappy:
Tarcisio
Tarcisio3mo ago
Isn't it just meaningless to have a transaction like the one above since SaveChangesAsync already works in the same fashion?
Want results from more Discord servers?
Add your server