TryUpdateModel - the model of type could not be updated - asp.net-mvc

I'm using Telerik's MVC Grid to edit some records in MVC3, using Razor view.
I call the edit on the controller using the following code:
public ActionResult _CategoriesUpdate(int id)
{
WR_TakeAway_Menu_Categories category = db.WR_TakeAway_Menu_Categories.Where(c => c.ID == id).Single();
TryUpdateModel(category);
db.ApplyCurrentValues(category.EntityKey.EntitySetName, category);
db.ObjectStateManager.ChangeObjectState(category, EntityState.Modified);
db.SaveChanges();
Although this updates the records in the serer, it keeps the grid in edit mode because it was unable to update all the properties of the "category".
If I change TryUpdateModel to UpdateModel it throws an error saying "the model of type WR_TakeAway_Menu_Categories could not be updated"
Is there a better way of doing this, or some way to allow TryUpdateModel to return true to allow the grid to return to display mode?

Without seeing your WR_TakeAway_Menu_Categories class, I'm going to assume that you have some other classes as properties of your WR_TakeAway_Menu_Categories class.
If that is the case, you'll need to exclude the custom objects from the TryUpdateModel method and set those manually before hand.
For example:
db.Entry(category).Reference(c => c.CreatedByUser).CurrentValue = CreatedByUser;
db.Entry(category).Reference(c => c.LastUpdateByUser).CurrentValue = LastUpdateByUser;
This will set your "custom object" variables to the latest value. I have noticed that in some cases if you do not do it this way, and instead just set the property explicitly, the database record will not always get updated.
After you have manually updated the custom properties, then call the TryUpdateModel, excluding the properties that you set manually.
TryUpdateModel<WR_TakeAway_Menu_Categories>(category, null, null, new[] { "CreatedByUser", "LastUpdateByUser" });

Related

how can i just update a part of then fields when table 's all fields are not nullable but have default value

mysql fields look like:
Entity Framework with mysql on existting database
my application is a mvc 4 project using EF 4.4 on mysql with a existting database.
how can i just update a part of then fields when table 's all fields are not nullable but have default value .
when create or update persistent to database for a part of field, EF will Automatically fill a null to those do not explicitly specified fields and i will get a exception.
i don't want modify database. what can i go with this? thank you
Edit:
my code like this... how make changes to it in your opinion?
[HttpPost]
public ActionResult Edit(Post_15 post)
{
if (ModelState.IsValid)
{
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
You must provide default values to your object (for example in constructor). EF doesn't play nicely with database default values. With default update EF always sends explicit value for each column. When you send explicit value, the default value the database is not used. If you don't set the value for property in the application, .NET default value is send to database.
Alternatively you must handle update in completely different way. You must explicitly set columns you are going to update to ensure that EF will not update other columns.
var entity = new YourEntity {
Id = 123,
ColumnToUpdate = "ABC"
};
objectContext.Attach(entity);
ObjectStateEntry entry = objectContext.ObjectStateManager.GetObjectStateEntry(entity);
entry.SetModifiedProperty("ColumnToUpdate");
objectContext.SaveChanges();
This code will update only ColumnToUpdate even if there are 20 other persisted properties.
Edit:
DbContext alternative:
var entity = new YourEntity {
Id = 123,
ColumnToUpdate = "ABC"
};
dbContext.Entities.Attach(entity);
DbStateEntry<Entity> entry = dbContext.Entry(entity);
entry.Property(e => e.ColumnToUpdate).IsModified = true;
dbContext.SaveChanges();
Side note: Only .NET 4.5 supports setting IsModified back to false.

How to bypass the System.Data.Entity.Internal.InternalPropertyEntry.ValidateNotDetachedAndInModel(String method) validation of Entity framework?

I'm using a customized method for tracking individual modified properties of an n-tier disconnected entity class. I extracted it from
Programming Entity Framework: DbContext by Julia Lerman and Rowan
Miller (O’Reilly). Copyright 2012 Julia Lerman and Rowan Miller,
978-1-449-31296-1.
The code is:
public void ApplyChanges<TEntity>(TEntity root) where TEntity : class, IObjectWithState {
// bind the entity back into the context
dbContext.Set<TEntity>().Add(root);
// throw exception if entity does not implement IObjectWithState
CheckForEntitiesWithoutStateInterface(dbContext);
foreach (var entry in dbContext.ChangeTracker.Entries<IObjectWithState>()) {
IObjectWithState stateInfo = entry.Entity;
if (stateInfo.State == RecordState.Modified) {
// revert the Modified state of the entity
entry.State = EntityState.Unchanged;
foreach (var property in stateInfo.ModifiedProperties) {
// mark only the desired fields as modified
entry.Property(property).IsModified = true;
}
} else {
entry.State = ConvertState(stateInfo.State);
}
}
dbContext.SaveChanges();
}
The purpose of this method is to let the EF know only a predefined set of entity fields are ready for update in the next call of SaveChanges(). This is needed in order to workaround the entity works in ASP.NET MVC 3 as follows:
on initial page load: the Get action of the controller is loading the
entity object and passing it as a parameter to the view.
The View generate controls for editing 2 of the fields of the entity,
and holds the ID of the record in a hidden field.
When hitting [save] and posting the entity back to the controller all
of the fields excepting the 3 preserved in the view comes with a null
value. This is the default behavior of the MVC binding manager.
If i save the changes back to the database the update query will of course overwrite the non mapped fields with a sentence as follows:
UPDATE non_mapped_field_1 = NULL, ..., mapped_field_1 = 'mapped_value_1', mapped_field_2 = 'mapped_value_2', ... non_mapped_field_n = NULL WHERE ID = mapped_field_3
This is the reason i'm trying to track the fields individually and update only those fields i'm interested in. before calling the custom method with ApplyChanges() i'm adding the list of fields i want to be included in the update to the IObjectWithState.ModifiedProperties list, in order to get a SQL statement as follows:
UPDATE mapped_field_1 = 'mapped_value_1', mapped_field_2 = 'mapped_value_2' WHERE id = mapped_value_3
The problem is, when marking one of the fields as modified in ApplyChanges, i.e.:
entry.Property(property).IsModified = true;
the system is throwing the following exception:
{System.InvalidOperationException: Member 'IsModified' cannot be called for property 'NotifyCEDeadline' on entity of type 'User' because the property is not part of the Entity Data Model.
at System.Data.Entity.Internal.InternalPropertyEntry.ValidateNotDetachedAndInModel(String method)
at System.Data.Entity.Internal.InternalPropertyEntry.set_IsModified(Boolean value)
at System.Data.Entity.Infrastructure.DbPropertyEntry.set_IsModified(Boolean value)
...
So the question is. There's a way to bypass this EF validation or let the context know of the existance of this system property (IsModified) that i'm trying to change?
Summary of the architeture:
EF Code first (annotation + Fluent API)
Oracle .NET EF Data provider (ODAC)
Context is injected to a cutom business context with nInject.MVC => this is the reason i customized the ApplyChanges() method from
using (var context = new BreakAwayContext()){
context.Set().Add(root);
to a simple call to the already initialized dbcontext
dbContext.Set().Add(root);
Oracle Database is created manually i.e. without the help of EF, so no EF metadata tables are used.
Thanks,
Ivan.
Very good description, however I can't find any information on why you need a transient property called "IsModified" in the object and/or why you need to tell EF about it being modified (EF won't be able to persist it anyway).
The value of the IsModified property should be set by the model binder if the property was incldued in the view anyway.
You could just add code in your ApplyChanges method to skip a property named "IsModified", or even better, filter only known properties using entry.CurrentValues.PropertyNames, e.g.:
foreach (var property in stateInfo.ModifiedProperties) {
// mark only the desired fields as modified
if (entry.CurrentValues.PropertyNames.Contains(property)) {
entry.Property(property).IsModified = true;
}
}
Update: Ivan, very sorry I did not understand the problem better when you posted it several months ago and that I did not follow up after your added these clarifying comments. I think I understand better now. That said, I think the code snippet that I offered can be part of the solution. From looking at the exception you are getting again, I understand now that the problem that EF is detecting is that NotifyCEDDealine is not a persistent property (i.e. it is not mapped in the Code First model to a column in the database). IsModified can only be used against mapped properties, therefore you have two options: you change the code of the implementation of IObjectWithState in your entities so that non-mapped properties are not recorded in ModifiedProperties, or you use my code snippet to prevent calling IsModified with those.
By the way, an alternative to doing all this is to use the Controller.TryUpdateModel API to set only the modified properties in your entities.
Hope this helps (although I understand it is very late).

What is the best way to maintain an entity's original properties when they are not included in MVC binding from edit page?

I have an ASP.NET MVC view for editing a model object. The edit page includes most of the properties of my object but not all of them -- specifically it does not include CreatedOn and CreatedBy fields since those are set upon creation (in my service layer) and shouldn't change in the future.
Unless I include these properties as hidden fields they will not be picked up during Binding and are unavailable when I save the modified object in my EF 4 DB Context. In actuality, upon save the original values would be overwritten by nulls (or some type-specific default).
I don't want to drop these in as hidden fields because it is a waste of bytes and I don't want those values exposed to potential manipulation.
Is there a "first class" way to handle this situation? Is it possible to specify a EF Model property is to be ignored unless explicitly set?
Use either:
public bool SaveRecording(Recording recording)
{
// Load only the DateTime property, not the full entity
DateTime oldCreatedOn = db.Recordings
.Where(r => r.Id == recording.Id)
.Select(r => r.CreatedOn)
.SingleOrDefault();
recording.CreatedOn = oldCreatedOn;
db.Entry(recording).State = EntityState.Modified;
db.SaveChanges();
return true;
}
(Edit: The query only loads the CreatedOn column from the database and is therefore cheaper and faster than loading the full entity. Because you only need the CreatedOn property using Find would be unnecessary overhead: You load all properties but need only one of them. In addition loading the full entity with Find and then detach it afterwards could be shortcut by using AsNoTracking: db.Recordings.AsNoTracking().SingleOrDefault(r => r.Id == recording.Id); This loads the entity without attaching it, so you don't need to detach the entity. Using AsNoTracking makes loading the entity faster as well.)
Edit 2
If you want to load more than one property from the database you can project into an anonymous type:
public bool SaveRecording(Recording recording)
{
// Load only the needed properties, not the full entity
var originalData = db.Recordings
.Where(r => r.Id == recording.Id)
.Select(r => new
{
CreatedOn = r.CreatedOn,
CreatedBy = r.CreatedBy
// perhaps more fields...
})
.SingleOrDefault();
recording.CreatedOn = originalData.CreatedOn;
recording.CreatedBy = originalData.CreatedBy;
// perhaps more...
db.Entry(recording).State = EntityState.Modified;
db.SaveChanges();
return true;
}
(End of Edit 2)
Or:
public bool SaveRecording(Recording recording)
{
Recording oldVersion = db.Recordings.Find(recording.Id);
recording.CreatedOn = oldVersion.CreatedOn;
// flag only properties as modified which did really change
db.Entry(oldVersion).CurrentValues.SetValues(recording);
db.SaveChanges();
return true;
}
(Edit: Using CurrentValues.SetValues flags only properties as Modified which indeed have been changed compared to the original state in the database. When you call SaveChanges EF will sent only the properties marked as modified in an UPDATE statement to the database. Whereas setting the state in Modified flags all properties as modified, no matter if they really changed or not. The UPDATE statement will be more expensive because it contains an update for all columns.)
If you don't want to send that data down to the client, I don't see any other option but to load up the original from the db in your service layer when you save and merge those original property values back in to the updated object. There's no way for EF to know that you didn't set those values to null on purpose and don't actually want to save them that way.
You could implement your own model binder that ignores the properties you don't want to pass around. Start here - http://lostechies.com/jimmybogard/2009/03/18/a-better-model-binder/
I think when you going to update use getById to get all the entity and then set your relevant properties and then you can update. It will be easy if you are using some kind of mapper (Automapper) to map your properties from view model to loaded entity from DB.
If you want to avoid making an additional (unnecessary) call to your database before every update, you can either use self-tracking entities or set StoreGeneratedPattern="Identity" for those fields in your entity model. And yes, Identity is misleading, but that sounds like the setting you'd want:
Identity A value is generated on insert and remains unchanged on update.
http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.storegeneratedpattern.aspx

Preventing EF4 ConstraintException when invoking TryUpdateModel

Given following ASP.NET MVC controller code:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
string[] whitelist = new []{ "CompanyName", "Address1", "Address2", ... };
Partner newPartner = new Partner();
if (TryUpdateModel(newPartner, whitelist, collection))
{
var db = new mainEntities();
db.Partners.AddObject(newPartner);
db.SaveChanges();
return RedirectToAction("Details/" + newPartner.ID);
}
else
{
return View();
}
}
The problem is with the Entity Framework 4: the example Partner entity is mapped to a database table with it's fields NOT ALLOWED to be NULL (which is ok by design - they're required).
Unfortunately, invoking TryUpdateModel when some of the properties are nulls produces as many ConstraintExceptions what is not expected! I do expect that TryUpdateModel return false in this case.
It is ok that EF wouldn't allow setting a property's value to null if it should not be, but the TryUpdateMethod should handle that, and add the error to ModelState errors collection.
I am wrong, or somebody screwed up the implementation of TryUpdateModel method?
It's not "screwed up". It's by design. My preferred way of dealing with this is to bind to an edit model rather than directly to an entity. If that's not an option for you, then you can write an associated metadata provider or initialize the properties.

Model Binding With Entity Framework (ASP.NET MVC)

Earlier I created an AddClient page that (when posted) passed a client object and I used db.AddToClient(obj) in my repository to persist it. Easy stuff.
Now, I have a details page whose save submits a post to an action "UpdateClient". Before that action is hit, my custom model binder creates my Client object and it's conveniently handed to the action. The thing is, this client object is not connected to a EF context yet. Where is the correct place to do that? In the modelbinder, or maybe when we get it from the controller, or perhaps we wait until we do a repository call and link it up there? What's the recommended process?
From what I remember, you will either need to attach the object again to the context and set it as modified
Or reload the object from the database and apply your changes.
This article explains it better:
http://msdn.microsoft.com/en-us/magazine/ee321569.aspx#id0090022
What version of EF are you using ?
If an EF object has been created outside a context, you need to Attach the object to the context.
See: http://msdn.microsoft.com/en-us/library/bb896271.aspx
I know this is an old thread but in the interest of new readers:
Based on my observations using VS 2012, MVC 4 and EF 4.0 with a view that has an EF object for a model that submits a form back to the controller.
On the controller:
public ActionResult SubmitEFObject(tblData data, FormCollection col)
"data" will only have the properties used in the view (#Html.xxxFor) filled.
It appears that when "data" is created, the posted FormCollection is used to set data's properties. If you had a property that wasn't used, DataID for example, then data.DataID will have a null/default value. Add a "#Html.Hidden(m => m.DataID)" to your view and THEN DataID will be filled.
As a 'quick n dirty' way to work with this, I created a method that would merge the incoming 'data' with the 'data' in the database and return the merged object:
// Note: error handling removed
public tblData MergeWithDB(DBContext db, tblData data, params string[] fields)
{
tblData d = db.tblData.Where(aa => aa.DataID == data.DataID).Single();
if (fields.Contains("Field1")) d.Field1 = data.Field1;
if (fields.Contains("Field2")) d.Field2 = data.Field2;
if (fields.Contains("Field3")) d.Field3 = data.Field3;
// etc...
return d;
}
On the controller:
public ActionResult SubmitEFObject(tblData data, FormCollection col)
{
DataEntities db = new DataEntities();
tblData d = MergeWithDB(db, data, col.AllKeys);
db.SaveChanges();
}
You could make this more generic using reflection or maybe more efficient by looping through the string[] fields instead of all the ifs but for my purposes this was 'good enough'.
Database work should be put in the repository call.
Are you directly binding to an entity framework object in your model binding? If not, you should consider do some mapping between your custom object and entity framework object.

Resources