Reputation: 7217
I'm using EF Core and .NET 6 and I would like to essentially upsert an entity to a table - a fairly simple ask.
I have the following code:
var countries = GetCountries();
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
foreach (var c in countries)
{
// check if the country already exists.
var exists = dbContext.Countries.Where(d => d.Id == c.Id).FirstOrDefault();
// if already exists - update (rather than add).
if (exists != null)
{
exists.Name = c.Name;
exists.DisplayName = c.DisplayName;
... // omitted other prop updates.
dbContext.Countries.Update(exists);
}
else
{
dbContext.Countries.Add(c);
}
}
await dbContext.SaveChangesAsync();
}
I was wondering - is there was a more efficient way to update without manually looking up then updating (it's not very performant).
Preferably, I was hoping there was a Merge
method in EF Core but can't find anything useful (that's free...). Rather than doing the manual lookup and update in this way.
I'm probably missing something very obvious here - thanks for any pointers in advance!
Upvotes: 2
Views: 9867
Reputation: 1
The answer by user19087368 seems the most straight forward. I tested it on .NET 6 and it worked perfectly - adapted a little bit to my usecase:
Here is my version of it with the "guid" as the primary key:
public async Task CreateOrUpdateApplication(Application application)
{
var itemExists = _dbContext
.Application
.Any(i => i.ApplicationGuid == application.ApplicationGuid);
_dbContext.Entry(application).State = itemExists ?
EntityState.Modified : EntityState.Added;
await _dbContext.SaveChangesAsync();
}
Upvotes: 0
Reputation: 27282
EF Core do not have Merge
, or similar for Upsert.
You can improve performance of your query by selecting existng items in one batch. Also you do not need to call Update
, just change properties.
var countries = GetCountries();
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var countyIds = countries.Select(c => c.Id);
var existing = (await dbContext.Countries.Where(d => countyIds.Contains(d.Id))
.ToListAsync())
.ToDictionary(c => c.Id);
foreach (var c in countries)
{
// check if the country already exists.
if (existing.TryGetValue(c.Id, out var toUpdate))
{
// if already exists - update (rather than add).
toUpdate.Name = c.Name;
toUpdate.DisplayName = c.DisplayName;
... // omitted other prop updates.
}
else
{
dbContext.Countries.Add(c);
}
}
await dbContext.SaveChangesAsync();
}
Upvotes: 5
Reputation: 53
public void InsertOrUpdate(Entity entity)
{
using (var context = new dbContext.Countries())
{
context.Entry(entity).State = entity.Id == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
}
Upvotes: -2