I want to upsert reference members of an existing entity.
Do I have to write specific code for the upsert?
meaning: I have to check if I'm handling an existing reference member or a new one.
Is there any other simple way to do so?
What happens when you do only Save
?
public void SaveCofiguration(MamConfiguration_V1Ui itemUi) { var itemEf = mMamConfiguration_V1UiToEfConvertor.ConvertToNewEf(itemUi); using (var maMDBEntities = new MaMDBEntities()) { IDal<MamConfiguration_V1> mamConfigurationDal = mDalFactory.GetDal<MamConfiguration_V1>(maMDBEntities); mamConfigurationDal.Save(itemEf); } } public MamConfiguration_V1 GetById(object id) { id.ThrowIfNull("id"); int configurationId = Convert.ToInt32(id); var result = mMaMDBEntities.MamConfiguration_V1.SingleOrDefault(item => item.ConfigurationId == configurationId); return result; } public MamConfiguration_V1 Save(MamConfiguration_V1 item) { item.ThrowIfNull("item"); var itemFromDB = GetById(item.ConfigurationId); if (itemFromDB != null) { UpdateEfItem(itemFromDB, item); // if (mMaMDBEntities.ObjectStateManager.GetObjectStateEntry(itemFromDB).State == EntityState.Detached) // { // mMaMDBEntities.MamConfiguration_V1.AddObject(itemFromDB); // } // Attached object tracks modifications automatically mMaMDBEntities.SaveChanges(); return item; } private void UpdateEfItem(MamConfiguration_V1 itemFromDb, MamConfiguration_V1 itemFromUi) { itemFromDb.UpdatedDate = DateTime.Now; itemFromDb.Description = itemFromUi.Description; itemFromDb.StatusId = itemFromUi.StatusId; itemFromDb.Name = itemFromUi.Name; itemFromDb.NumericTraffic = itemFromUi.NumericTraffic; itemFromDb.PercentageTraffic = itemFromUi.PercentageTraffic; itemFromDb.Type = itemFromUi.NumericTraffic; foreach (var item in itemFromDb.MamConfigurationToBrowser_V1.ToList()) { if (itemFromUi.MamConfigurationToBrowser_V1.All(b => b.BrowserVersionId != item.BrowserVersionId)) { mMaMDBEntities.MamConfigurationToBrowser_V1.DeleteObject(item); } } for (int i = 0; i < itemFromUi.MamConfigurationToBrowser_V1.Count; i++) { var element = itemFromUi.MamConfigurationToBrowser_V1.ElementAt(i); var item = itemFromDb.MamConfigurationToBrowser_V1.SingleOrDefault(b => b.BrowserVersionId == element.BrowserVersionId); if (item != null) { // copy properties from element to item } else { element.Browser = mMaMDBEntities.Browsers.Single(browserItem => browserItem.BrowserID == element.BrowserID); //element.MamConfiguration_V1 = itemFromDb; //have also tried: element.MamConfiguration_V1 = null; //element.MamConfiguration_V1Reference = null; itemFromDb.MamConfigurationToBrowser_V1.Add(element); } } }
But I would have expecte Save(itemUi)
and SaveChanges()
to work fine. No?
We can update records either in connected or disconnected scenarios. In the connected Scenario, we open the context, query for the entity, edit it, and call the SaveChanges method. In the Disconnected scenario, we already have the entity with use. Hence all we need to is to attach/add it to the context.
The term upsert is a portmanteau – a combination of the words “update” and “insert.” In the context of relational databases, an upsert is a database operation that will update an existing row if a specified value already exists in a table, and insert a new row if the specified value doesn't already exist.
To update an entity with Entity Framework Core, this is the logical process: Create instance for DbContext class. Retrieve entity by key. Make changes on entity's properties.
public void InsertOrUpdate(DbContext context, UEntity entity) { context.Entry(entity).State = entity.Id == 0 ? EntityState.Added : EntityState.Modified; context.SaveChanges(); }
http://forums.asp.net/t/1889944.aspx/1
To avoid the overhead of a query and then insert, or throwing exceptions, you can take advantage of the underlying database support for merges or upserts.
This nuget package does the job pretty well: https://www.nuget.org/packages/FlexLabs.EntityFrameworkCore.Upsert/
Github: https://github.com/artiomchi/FlexLabs.Upsert
Example:
DataContext.DailyVisits .Upsert(new DailyVisit { // new entity path UserID = userID, Date = DateTime.UtcNow.Date, Visits = 1, }) // duplicate checking fields .On(v => new { v.UserID, v.Date }) .WhenMatched((old, @new) => new DailyVisit { // merge / upsert path Visits = old.Visits + 1, }) .RunAsync();
The underlying generated sql does a proper upsert. This command runs right away and does not use change tracking, so that is one limitation.
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