I am having a concurrency Exception when I tried to update MessageTemplate and TemplateLookup table. MessageTemplate table update fine but the error occur when the code tried to update TemplateLookup table. Any help will be appreciated
Error
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions."
Controller
public async Task<ActionResult> Edit (MessageTemplate messagetemplate,int Id, bool Enable, int id)
{
TemplateLookup template = new TemplateLookup();
var appdata = DateTime.Now;
try
{
if (ModelState.IsValid)
{
var currentUser = await _db.vwUsers.FirstOrDefaultAsync(i => i.DomainUserName == User.Identity.Name);
if (currentUser != null)
messagetemplate.LastUpdatedByUser = currentUser.FullName;
messagetemplate.LastUpdatedByUserID = User.Identity.Name;
messagetemplate.LastUpdatedOn = appdata;
//messagetemplate.Id = Id;
_db.Entry(messagetemplate).State = EntityState.Modified;
//await _db.SaveChangesAsync();
if (Enable == false)
{
var templateidlist = _db.TemplateLookups.Where(v => v.TemplateId == Id).ToList();
messagetemplate.Enable = Enable;
foreach (var templateid in templateidlist)
{
template.TemplateActive = Enable;
template.LastUpdatedOn = appdata;
template.LastUpdatedByUser = currentUser.FullName;
template.TemplateId = Id;
// Error occur here
_db.Entry(template).State = EntityState.Modified;
}
}
_db.Entry(messagetemplate).State = EntityState.Modified;
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(messagetemplate);
}
}
Well as it says - it looks like the row is being modified in between your query being started and actually saved...
I noticed you change the Id:
template.TemplateId = Id;
which you also search on;
var templateidlist = _db.TemplateLookups.Where(v => v.TemplateId == Id).ToList();
So if this action is run twice with the same template Ids it may change them before the second one has a chance to run.
Ususally in this concurrent modification scenario you'd catch the exception and re-display the form with the new values - but it depends on your usecase we can't say without more information about what your application does...
You can read about various options to handle it here: https://learn.microsoft.com/en-us/ef/ef6/saving/concurrency
Currently I am doing like this:
For Example:
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
db.Entry(oldobj).CurrentValues.SetValues(model);
}
It works, but for example,
I have 50 columns in my table but I displayed only 25 fields in my form (I need to partially update my table, with remaining 25 column retain same old value)
I know it can be achieve by "mapping columns one by one" or by creating "hidden fields for those remaining 25 columns".
Just wondering is there any elegant way to do this with less effort and optimal performance?
This is a very good question. By default I have found that as long as change tracking is enabled (it is by default unless you turn it off), Entity Framework will do a good job of applying to the database only what you ask it to change.
So if you only change 1 field against the object and then call SaveChanges(), EF will only update that 1 field when you call SaveChanges().
The problem here is that when you map a view model into an entity object, all of the values get overwritten. Here is my way of handling this:
In this example, you have a single entity called Person:
Person
======
Id - int
FirstName - varchar
Surname - varchar
Dob - smalldatetime
Now let's say we want to create a view model which will only update Dob, and leave all other fields exactly how they are, here is how I do that.
First, create a view model:
public class PersonDobVm
{
public int Id { get; set; }
public DateTime Dob { get; set; }
public void MapToModel(Person p)
{
p.Dob = Dob;
}
}
Now write the code roughly as follows (you'll have to alter it to match your context name etc):
DataContext db = new DataContext();
Person p = db.People.FirstOrDefault();
// you would have this posted in, but we are creating it here just for illustration
var vm = new PersonDobVm
{
Id = p.Id, // the Id you want to update
Dob = new DateTime(2015, 1, 1) // the new DOB for that row
};
vm.MapToModel(p);
db.SaveChanges();
The MapToModel method could be even more complicated and do all kinds of additional checks before assigning the view model fields to the entity object.
Anyway, the result when SaveChanges is called is the following SQL:
exec sp_executesql N'UPDATE [dbo].[Person]
SET [Dob] = #0
WHERE ([Id] = #1)
',N'#0 datetime2(7),#1 int',#0='2015-01-01 00:00:00',#1=1
So you can clearly see, Entity Framework has not attempted to update any other fields - just the Dob field.
I know in your example you want to avoid coding each assignment by hand, but I think this is the best way. You tuck it all away in your VM so it does not litter your main code, and this way you can cater for specific needs (i.e. composite types in there, data validation, etc). The other option is to use an AutoMapper, but I do not think they are safe. If you use an AutoMapper and spelt "Dob" as "Doob" in your VM, it would not map "Doob" to "Dob", nor would it tell you about it! It would fail silently, the user would think everything was ok, but the change would not be saved.
Whereas if you spelt "Dob" as "Doob" in your VM, the compiler will alert you that the MapToModel() is referencing "Dob" but you only have a property in your VM called "Doob".
I hope this helps you.
I swear by EntityFramework.Extended. Nuget Link
It lets you write:
db.Person
.Where(x => x.ID == model.ID)
.Update(p => new Person()
{
Name = newName,
EditCount = p.EditCount+1
});
Which is very clearly translated into SQL.
Please try this way
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
// Newly Inserted Code
var UpdatedObj = (Person) Entity.CheckUpdateObject(oldobj, model);
db.Entry(oldobj).CurrentValues.SetValues(UpdatedObj);
}
public static object CheckUpdateObject(object originalObj, object updateObj)
{
foreach (var property in updateObj.GetType().GetProperties())
{
if (property.GetValue(updateObj, null) == null)
{
property.SetValue(updateObj,originalObj.GetType().GetProperty(property.Name)
.GetValue(originalObj, null));
}
}
return updateObj;
}
I have solved my Issue by using FormCollection to list out used element in form, and only change those columns in database.
I have provided my code sample below; Great if it can help someone else
// Here
// collection = FormCollection from Post
// model = View Model for Person
var result = db.Person.Where(x => x.ID == model.ID).SingleOrDefault();
if (result != null)
{
List<string> formcollist = new List<string>();
foreach (var key in collection.ToArray<string>())
{
// Here apply your filter code to remove system properties if any
formcollist.Add(key);
}
foreach (var prop in result.GetType().GetProperties())
{
if( formcollist.Contains(prop.Name))
{
prop.SetValue(result, model.GetType().GetProperty(prop.Name).GetValue(model, null));
}
}
db.SaveChanges();
}
I still didn't find a nice solution for my problem, so I created a work around. When loading the Entity, I directly make a copy of it and name it entityInit. When saving the Entity, I compare the both to see, what really was changed. All the unchanged Properties, I set to unchanged and fill them with the Database-Values. This was necessary for my Entities without Tracking:
// load entity without tracking
var entityWithoutTracking = Context.Person.AsNoTracking().FirstOrDefault(x => x.ID == _entity.ID);
var entityInit = CopyEntity(entityWithoutTracking);
// do business logic and change entity
entityWithoutTracking.surname = newValue;
// for saving, find entity in context
var entity = Context.Person.FirstOrDefault(x => x.ID == _entity.ID);
var entry = Context.Entry(entity);
entry.CurrentValues.SetValues(entityWithoutTracking);
entry.State = EntityState.Modified;
// get List of all changed properties (in my case these are all existing properties, including those which shouldn't have changed)
var changedPropertiesList = entry.CurrentValues.PropertyNames.Where(x => entry.Property(x).IsModified).ToList();
foreach (var checkProperty in changedPropertiesList)
{
try
{
var p1 = entityWithoutTracking.GetType().GetProperty(checkProperty).GetValue(entityWithoutTracking);
var p2 = entityInit.GetType().GetProperty(checkProperty).GetValue(entityInit);
if ((p1 == null && p2 == null) || p1.Equals(p2))
{
entry.Property(checkProperty).CurrentValue = entry.Property(checkProperty).OriginalValue; // restore DB-Value
entry.Property(checkProperty).IsModified = false; // throws Exception for Primary Keys
}
} catch(Exception) { }
}
Context.SaveChanges(); // only surname will be updated
This is way I did it, assuming the new object has more columns to update that the one we want to keep.
if (theClass.ClassId == 0)
{
theClass.CreatedOn = DateTime.Now;
context.theClasses.Add(theClass);
}
else {
var currentClass = context.theClasses.Where(c => c.ClassId == theClass.ClassId)
.Select(c => new TheClasses {
CreatedOn = c.CreatedOn
// Add here others fields you want to keep as the original record
}).FirstOrDefault();
theClass.CreatedOn = currentClass.CreatedOn;
// The new class will replace the current, all fields
context.theClasses.Add(theClass);
context.Entry(theClass).State = EntityState.Modified;
}
context.SaveChanges();
In EF you can do like this
var result = db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
if(result != null){
result.Name = newName;
result.DOB = newDOB;
db.Person.Update(result);
}
Or you can use
using (var db= new MyDbContext())
{
var result= db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
result.Name= newName;
result.DOB = newDOB;
db.Update(result);
db.SaveChanges();
}
For more detail please EntityFramework Core - Update Only One Field
No Worry guys
Just write raw sql query
db.Database.ExecuteSqlCommand("Update Person set Name='"+_entity.Name+"' where Id = " + _entity.ID + "");
I am making an MVC4 web application using Entity Framework 5 (Database-first with generated POCOs) for data access.
In the app, the user goes through several screens, creating or editing a document (called a 'case study'). When they arrive at the final screen, their document exists as a CaseStudy POCO in memory, and everything is great until it is time to save this structure to the database.
To store the document, I have defined several database tables, which in turn map to EF POCOs used by the business layer, which is then consumed by the MVC controllers. As such, short-lived DbContexts are used to retrieve POCOs and store them in session between requests.
As a result, the save screen must save the contents of this POCO that has navigational properties to existing table data (Category, Layout, and Sections tables), and also added or updated data (CaseStudySections and the CaseStudy itself). So all of the POCOs are either new, or the context used to retrieve them has long been disposed. In other words, they are all 'detached'.
What is unusual about this post is that I already have a working solution in hand. The problem is that it is bulky, brittle, and inelegant. I am posting the code below. Note the iteration through sub-collections, the explicit adds and attaches, having to get an entry object and mark individual properties as modified just so they will be updated, and the awful song and dance at the end to get the AdditionalMaterials collection synced up. If this is what is required to deal with detached POCOs in EF5 I will be disappointed.
Am I missing something here? Is this consistent with best practices? Is there a more graceful and/or concise way to attach a structure of POCOs and insert/update?
The code to save a case study:
public void SaveCaseStudy(CaseStudy caseStudy)
{
foreach (var s in caseStudy.CaseStudySections)
{
this.Entities.Sections.Attach(s.Section);
if (s.CreatedByRefId == default(Guid))
{
s.CreatedByRefId = this.UserRefId;
s.CreatedTime = DateTime.Now;
this.Entities.CaseStudySections.Add(s);
}
else
{
this.Entities.CaseStudySections.Attach(s);
var entry = this.Entities.Entry(s);
entry.Property(e => e.TextData).IsModified = true;
entry.Property(e => e.BinaryData).IsModified = true;
}
s.LastModifiedByRefId = this.UserRefId;
s.LastModifiedTime = DateTime.Now;
}
foreach (var m in caseStudy.AdditionalMaterials)
{
if (m.CreatedByRefId == default(Guid))
{
m.CreatedByRefId = this.UserRefId;
m.CreatedTime = DateTime.Now;
this.Entities.AdditionalMaterials.Add(m);
}
else
{
this.Entities.AdditionalMaterials.Attach(m);
}
m.LastModifiedByRefId = this.UserRefId;
m.LastModifiedByTime = DateTime.Now;
}
this.Entities.Layouts.Attach(caseStudy.Layout);
this.Entities.Categories.Attach(caseStudy.Category);
if (caseStudy.CreatedByRefId != default(Guid))
{
this.Entities.CaseStudies.Attach(caseStudy);
var entry = this.Entities.Entry(caseStudy);
entry.Property(e => e.CaseStudyName).IsModified = true;
entry.Property(e => e.CaseStudyTitle).IsModified = true;
}
else
{
this.Entities.CaseStudies.Add(caseStudy);
caseStudy.CreatedByRefId = this.UserRefId;
caseStudy.CreatedTime = DateTime.Now;
}
caseStudy.LastModifiedByRefId = this.UserRefId;
caseStudy.LastModifiedTime = DateTime.Now;
if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized)
{
caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval;
}
caseStudy.ApprovedByRefId = null;
caseStudy.ApprovedTime = null;
this.Entities.SaveChanges();
var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials
.Select(m => m.AdditionalMaterialRefId)
.ToArray();
var additionalMaterialsToRemove = this.Entities.AdditionalMaterials
.Where(m =>
m.CaseStudyRefId == caseStudy.CaseStudyRefId &&
!existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId))
.ToArray();
foreach (var additionalMaterialToRemove in additionalMaterialsToRemove)
{
this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove);
}
this.Entities.SaveChanges();
}
In general it is what you have to do. You must tell EF about each change you want to perform when attaching detached object graph. I don't say that your code cannot be simplified but you will still have to deal with every entity and setting its state if you want it to be added or modified.
Here is little bit older but still valid answer about the topic - in short nothing has changes since I wrote it, only new DbContext API was created which still sits on top of the old API. The best description of this topic I have seen so far is in book Programming Entity Framework: DbContext.
How about just doing:
db.CaseStudies.Attach(caseStudy);
db.Entry(caseStudy).State = EntityState.Modified;
db.SaveChange();
That will save all changes in your model to the db.
I am looking for a more better way to update a record using Entity Framework.
Below is what I am using now, where playerFromModel is data fetched from View.
public bool UpdatePlayer(PlayerEntity playerFromModel)
{
bool updateSuccessfull = false;
using (var context = new PlayerEntities())
{
var player = context.Player.Where(m => m.emailAddress == playerFromModel.EmailAddress).FirstOrDefault();
if (player != null)
{
player.emailAddress = playerFromModel.EmailAddress;
player.first_name = playerFromModel.FirstName;
player.last_name = playerFromModel.LastName;
player.alt_email_id1 = playerFromModel.AlternateEmailAddress;
player.street = playerFromModel.Street;
player.city = playerFromModel.City;
player.state = playerFromModel.State;
player.zip = playerFromModel.Zip;
player.country_code = playerFromModel.CountryCode;
player.phone1 = playerFromModel.Phone;
try
{
context.SaveChanges();
updateSuccessfull = true;
}
catch
{
updateSuccessfull = false;
}
}
}
return updateSuccessfull;
}
As you can see I have to manually map each of the fields and the same approach I have followed everywhere.
I was thinking that there definitely has to be a better way to do this.
Please guide me on this. Thanks.
You can just use TryUpdateModel. e.g.
bool updateSuccessfull = false;
using (var context = new PlayerEntities())
{
var player = context.Player.Where(m => m.emailAddress == playerFromModel.EmailAddress).FirstOrDefault();
if (player != null)
{
//Beware this will try to map anything it can. This can be dangerous
if(TryUpdateModel(player)){
try
{
context.SaveChanges();
updateSuccessfull = true;
}
catch
{
updateSuccessfull = false;
}
}
}
}
return updateSuccessfull;
}
I wouldn't though see here Real example of TryUpdateModel, ASP .NET MVC 3.
You could use Automapper or something similar as MiBu said. Create a ViewModel link is here of the Player and then map from that to the entity
//Get a PlayerUpdate ViewModel
using (var context = new PlayerEntities())
{
// fetch the domain model that we want to update - BTW I'd use a repository pattern but that is another debate
var player = context.Player.Where(m => m.emailAddress == playerFromModel.EmailAddress).FirstOrDefault();
if (player != null)
{
// Use AutoMapper to update only the properties of this domain model
// that are also part of the view model and leave the other properties unchanged
AutoMapper.Map<UpdatePlayerViewModel , PlayerEntity>(viewModel, player);
try
{
context.SaveChanges();
updateSuccessfull = true;
}
catch
{
updateSuccessfull = false;
}
}
However I am of the opinion that updating entity properties is a significant thing and shouldn't be done automatically. Others feel the same. Jimmy Bogard who created AutoMapper doesn't seem to believe it needs two way mapping (However he says that is partly as they built AutoMapper for their requirement) Similar answer here on Stackoverflow saying do it yourself.
It depends on the complexity of your application but I would look at using the command pattern to send a message to an appropriate handler containing your properties and have the handler update them. If it was successful we do one thing if it wasn't we do another. Same pattern is described in MVC in Action. See similar (here is the link)[http://www.paulstovell.com/clean-aspnet-mvc-controllers] and here is the second link
I have the following question:
It is easy to insert an oBject in database with a form.
Just create an object
link it to the fields in your from.
Post back to controller,
create a new datacontext and do datacontext.InsertOnSubmit(object)
.
public static void AddPage(string lang, Page page)
{
using (var db = new CardReaderDataContext())
{
page.Lang = lang;
page.URL = UrlHelper.CreateValidSeoUrl(page.Name, "-");
db.Pages.InsertOnSubmit(page);
db.SubmitChanges();
}
}
But if you want to update an object, it is a tedious job.
You do the same flow,
you get the object,
link it to your form,
post it, but THEN !!!
because it went outside your datacontext, you have to reload the object from the datacontext,
transfer all the variables and save it,
this is a little complex explained so I give an example:
To update an object that you modified in a form:
public static void Update(Page page)
{
using (var db = new CardReaderDataContext())
{
var _page = db.Pages.Where(p => p.Guid == page.Guid).Single();
_page.ModificationDate = DateTime.Now;
_page.Title = page.Title;
_page.Description = page.Description;
_page.Content = page.Content;
_page.Keywords = page.Keywords;
_page.Name = page.Name;
_page.WTLang = page.WTLang;
_page.WTSKU = page.WTSKU;
_page.WTTi = page.WTTi;
_page.WTUri = page.WTUri;
_page.URL = UrlHelper.CreateValidSeoUrl(page.Name, "-");
// _page.Order = GetMaxOrderByMenuGuid(page.MenuGuid);
db.SubmitChanges();
}
}
I don't know if it is clear, if it isn't comment me, I will edit
I think you're looking for DataContext.Attach, but you can only use that with linqtosql objects that have been serialised/deserialised.
Have a read of the answer to this question -
http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/384a1c03-3acf-43ef-9a25-b84f93025e63/
"It's also not a good idea to even
attempt to fetch the old version. By
doing that you are in effect turning
off optimistic concurrency, so unless
you intended that this is a bad
approach. What you need to do is
round trip both the original state and
the current state of the object."