I have an entity framework object model with two entities:
Alert (1-*) ----- (1) Check
The Check table has a unique constraint on the column UniqueProperty.
Checks are usually pre-existing entities in my database and any new alert should be added to existing checks.
I create a simple object graph somewhere in my code:
var alert = new Alert();
alert.Check = new Check { UniqueProperty = someValue };
Sometime later I'd like to persist my object graph:
using (var context = new MyContext())
{
context.Alerts.AddObject(alert);
// Replace temp check with actual database check if available.
var checkFromDb = context.Checks.SingleOrDefault(
c => c.UniqueProperty = alert.Check.UniqueProperty);
if (checkFromDb != null)
{
alert.Check = checkFromDb;
}
context.SaveChanges();
}
So, when there is a corresponding check in the database, use that one, otherwise do nothing (and it will simply be added).
The code above causes a unique constraint violation on the UniqueProperty constraint. The reason is that EF remembers the first check, even though I replace it later with the check from the database.
How can I get rid of that first check?
Don't set up the check until you're ready to save. If one already exists, add the alert to the existing check's alerts collection. If it doesn't, create a new one associate with the check, then add the alert to the db.
var alert = new Alert();
...
using (var context = new MyContext())
{
// Replace temp check with actual database check if available.
var checkFromDb = context.Checks.SingleOrDefault(
c => c.UniqueProperty = alert.Check.UniqueProperty);
if (checkFromDb != null)
{
checkFromDb.Alerts.Add( alert );
}
else
{
alert.Check = new Check { UniqueProperty = some value };
context.Alerts.AddObject(alert);
}
context.SaveChanges();
}
Related
I am working with SQL Geography types and since EFCore doesn't support type geography, I need to execute a stored proc to update my entity.
This works well, but when I call the row that has just been updated, Its returning the old value.
I can see the correct value in the DB.
Here is some of my code:
var FlId = new SqlParameter("#flId", SqlDbType.Int) { Value = testModel.Flid ?? SqlInt32.Null };
var OID = new SqlParameter("#oID", SqlDbType.Int) { Value = testModel.OID };
var flName = new SqlParameter("#flName", SqlDbType.VarChar) { Value = testModel.FLName };
var result = _dbContext.Database.ExecuteSqlCommand("testSchema.spUpsertOFL #flId, #oID, #flName,
parameters: new[] { FlId , OID , flName });
The above code works and performs the upsert, but when I then run a regular query using EFCore, I get back a stale record.
var TestQuery = _dbContext.Fl.FirstOrDefault(x => x.FLCode == testModel.Flcode && x.OID == testModel.OID);
I tried reloading the context with:
_dbContext.Entry(fl).Reload();
But I got an error saying :
"There was an internal error creating the Fl. The instance of entity type 'Fl' cannot be tracked because another instance with the same key value for {'FlID'} is already being tracked."
If I use postman and hit my get endpoint - the correct result returns.
Try detaching the entry and then requerying
dbContext.Entry(entry).State = EntityState.Detached;
entry = context.Users.FirstOrDefault(e => e.Id == id);
While researching this problem I saw many people say the best course of action is to dispose and create a new dbcontext https://github.com/dotnet/efcore/issues/16861
The next most common solution I saw was to call dbContext.Entry(entry).Reload(); This did not work for me because I was changing the type of an entry via a discriminator. Detaching the old entry means when you request it again it pulls from the database instead of the local cache
I have a disconnected entity framework graph that is sent to the client and returned with updates. One of the updates may replace an entity in the middle of the graph. When I try to replace it, I get an InvalidOperationException with the message:
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
For simplicity, the model would look something like this:
The code that's causing the exception would look like this:
// Create a tree of objects
Root root = new Root() { Id = 1 };
Branch origBranch = new Branch() { Id = 3 };
Twig onlyTwig = new Twig() { Id = 5 };
Leaf onlyLeaf = new Leaf() { Id = 7 };
onlyTwig.Leaves.Add(onlyLeaf);
origBranch.Twigs.Add(onlyTwig);
root.Branches.Add(origBranch);
// Store the structure in the database using the container
using (Pot container1 = new Pot())
{
container1.Roots.Add(root);
container1.SaveChanges();
}
// Create a new Branch to replace the original
Branch newBranch = new Branch() { Id = 11 };
// Add the Twig from the original object
newBranch.Twigs.Add(onlyTwig);
using (Pot container2 = new Pot())
{
container2.Roots.Attach(root);
// Replace the branch
root.Branches.Remove(origBranch);
root.Branches.Add(newBranch);
container2.SaveChanges(); // THROWS EXCEPTION !!
}
I thought by removing the old entity, then adding a new one that I would satisfy the "new relationship must be defined..." criteria, but it's failing. In our case, making the column nullable in the database leads to other issues, the first of which is risking database integrity. So how is this normally handled?
I resolved part of the issue by essentially tricking entity framework into believing it was making an update in place, rather than replacing the item with a new item. The key to the solution is setting the same primary key value, then setting the entity state to Modified The replacement code is posted below.
// Create a new Branch to replace the original
// Make sure to use the id from the original saved object
Branch newBranch = new Branch() { Id = origBranch.Id };
// Add the Twig from the original object
newBranch.Twigs.Add(onlyTwig);
// Replace the original branch with the new branch
root.Branches.Remove(origBranch);
root.Branches.Add(newBranch);
using (Pot container2 = new Pot())
{
// Attach the graph to the container. The default state is unchanged.
container2.Roots.Attach(root);
// Trick entity framework into thinking the new branch with the
// same primary key is the original item with modifications
container2.Entry(newBranch).State = EntityState.Modified;
container2.SaveChanges();
}
However, there are occasions to replace the entity with an entirely new entity, so I still need an answer for how to remove then add.
I've stumbled upon a strange bug in my code. Which was working before, but now works sometimes.
I am using EF6 to Edit an entity with some relations.
To not edit the relations I 'Attach' them (see example code).
public void EditA(A ThisIsA, B ThisIsB)
{
using (var Context = new LDZ_DEVEntities())
{
Context.As.Attach(ThisIsA);
var b = Context.Bs.FirstOrDefault(x => x.BId == ThisIsB.BId);
//var b = Context.Bs.Find(ThisIsB.BId);
if (b != null)
Context.Bs.Attach(b);
else
b = ThisIsB;
if (b.C != null)
Context.Cs.Attach(b.C);
ThisIsA.Bs.Add(b);
Context.SaveChanges();
}
}
I've edited the names to keep it simple.
The following line
Context.Cs.Attach(b.C);
throws this error:
Attaching an entity of type 'C' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
This line was introduced because all the C entities are static entities. I never want a C to be created. If I remove this line, every time when I will add a B to A; a C is created. Which is not desirable.
Extra info:
A has a list of B's
B has one C
This EditA() Method is being called at multiple places in my software. This error only appears when the method is called in a loop (import). There are no problems while working on the first record. But I’m getting the error in the records after the first one.
I've read this questions plus answers but they weren't working for me:
ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value
Attaching an entity of type failed because another entity of the same type already has the same primary key value
I fixed it.
In Fabio Luz his answer, he said:
//if A has been loaded from context
//dont attach it
//if it has been created outside of the context
//Context.Entry(ThisIsA).State = EntityState.Modified;
This got me thinking, so I edited my code to this:
public void EditA(A ThisIsA, B ThisIsB)
{
using (var Context = new LDZ_DEVEntities())
{
var a = Context.As.Find(ThisIsA.AId);
//var b = Context.Bs.FirstOrDefault(x => x.BId == ThisIsB.BId);
var b = Context.Bs.Find(ThisIsB.BId);
if (b != null)
Context.Bs.Attach(b);
else
b = ThisIsB;
if (b.C != null)
Context.Cs.Attach(b.C);
a.Bs.Add(b);
Context.SaveChanges();
}
}
Summary of changes:
Changed FirstOrDefault to Find
Get A from Context
At first I removed the Attach of C, as a result this created a new entity.
So I reversed this change.
Special thanks to Fabio Luz. I couldn't have done this without your help!
Take a look at the following link https://msdn.microsoft.com/en-us/data/jj592676.aspx
If you have an entity that you know already exists in the database but to which changes may have been made then you can tell the context to attach the entity and set its state to Modified. For example:
var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };
using (var context = new BloggingContext())
{
context.Entry(existingBlog).State = EntityState.Modified;
// Do some more work...
context.SaveChanges();
}
NOTE: you don't have to do this with all objects (A, B and C), just with A.
EDIT 1
Based on your comment, try this:
//check if
var _b = Context.Bs.Find(ThisIsB.BId);
if (_b != null)
//b doesn't exist, then add to the context
//make sure that the primary key of A is set.
//_b.PrimaryKeyOfA = someValue;
Context.Bs.Add(_b);
else
//b already exists, then modify the properties
//make sure that the primary key of A is set.
Context.SaveChanges();
EDIT 2
I didn't tested but it should work.
public void EditA(A ThisIsA, B ThisIsB)
{
using (var Context = new LDZ_DEVEntities())
{
//if A has been loaded from context
//dont attach it
//if it has been created outside of the context
//Context.Entry(ThisIsA).State = EntityState.Modified;
var _b = Context.Bs.Find(ThisIsB.BId);
if (_b == null)
{
_b = ThisIsB;
}
ThisIsA.Bs.Add(_b);
Context.SaveChanges();
}
}
Another way, depending on your situation, is to simply Detach the Entity State.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Modify(Model model)
{
if (model.Image == null)
{
Model item = db.Model.Find(model.Name);
// Get the Content needed:
model.Image = item.Image;
// Detach the Comparison State:
db.Entry(item).State = EntityState.Detached;
}
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
By doing this: db.Entry(item).State = EntityState.Detached; the State of the EntityFramework is still intact and you can save the changes into the Database (db).
Hope this helps!
Question
Why is EF first inserting a child object (PersonnelWorkRecord) with a dependency, before the object that it is depended on (TimesheetActivity). Also what are my options on correcting this?
ERD (simplified)
This is predefined by another system out of my direct control.
EF setup and save code
I am not sure I understand why/how Entity Framework is inserting the objects I have in the order it does however here is the code I am using to insert a parent and several children.
using (var db = new DataContext(user))
{
timesheet.State = State.Added;
timesheet.SequenceNumber = newSequenceNumber;
this.PrepareAuditFields(timesheet);
//To stop EF from trying to add all child objects remove them from the timehseets object.
timesheet = RemoveChildObjects(timesheet, db);
//Add the Timesheet object to the database context, and save.
db.Timesheets.Add(timesheet);
result = db.SaveChanges() > 0;
}
SQL Trace of EF's Inserts
When I run the code I get a SQL foreign key violation on the PersonnelWorkRecord (TimesheetActivityID) because I have not yet added the Activity (see trace).
exec sp_executesql N'insert [dbo].[Timesheets]([ProjectID], [TimesheetStatusID], ...
exec sp_executesql N'insert [dbo].[PersonnelWorkdays]([TimesheetID], [PersonnelID], ...
exec sp_executesql N'insert [dbo].[PersonnelWorkRecords]([PersonnelWorkdayID],[TimesheetActivityID], ...
Data Context Summary
modelBuilder.Entity<PersonnelWorkday>().HasRequired(pwd => pwd.Personnel).WithMany(p => p.PersonnelWorkdays).HasForeignKey(pwd => pwd.PersonnelID).WillCascadeOnDelete(false);
modelBuilder.Entity<PersonnelWorkday>().HasRequired(pwd => pwd.Timesheet).WithMany(t => t.PersonnelWorkdays).HasForeignKey(pwd => pwd.TimesheetID).WillCascadeOnDelete(false);
modelBuilder.Entity<PersonnelWorkRecord>().HasRequired(pwr => pwr.PersonnelWorkday).WithMany(pwd => pwd.PersonnelWorkRecords).HasForeignKey(pwr => pwr.PersonnelWorkdayID).WillCascadeOnDelete(false);
modelBuilder.Entity<PersonnelWorkRecord>().HasRequired(pwr => pwr.TimesheetActivity).WithMany(ta => ta.PersonnelWorkRecords).HasForeignKey(pwr => pwr.TimesheetActivityID).WillCascadeOnDelete(false);
modelBuilder.Entity<TimesheetActivity>().HasRequired(ta => ta.ProjectActivity).WithMany(a => a.TimesheetActivities).HasForeignKey(ta => ta.ProjectActivityCodeID).WillCascadeOnDelete(false);
modelBuilder.Entity<TimesheetActivity>().HasOptional(ta => ta.Facility).WithMany(f => f.TimesheetActivities).HasForeignKey(tf => tf.FacilityID).WillCascadeOnDelete(false);
modelBuilder.Entity<TimesheetActivity>().HasRequired(ta => ta.Timesheet).WithMany(t => t.TimesheetActivities).HasForeignKey(ta => ta.TimesheetID).WillCascadeOnDelete(false);
Remove Child Objects
Here is the code for the child objects method. I added this method to remove the objects from the timesheets' child objects related objects that are not foreign keys. For example I have a Crew object but I also have a CrewID foreign key, so I have set Crew = null so that EF does not try to insert it since it already exists.
private Timesheet RemoveChildObjects(Timesheet timesheet, DataContext db)
{
timesheet.Crew = null;
timesheet.Foreman = null;
timesheet.Location = null;
timesheet.Project = null;
timesheet.SigningProjectManager = null;
timesheet.TimesheetStatus = null;
timesheet.Creator = null;
timesheet.Modifier = null;
if (timesheet.TimesheetActivities != null)
{
foreach (TimesheetActivity tsa in timesheet.TimesheetActivities)
{
tsa.Creator = null;
if (tsa.EquipmentWorkRecords != null)
{
tsa.EquipmentWorkRecords = RemoveChildObjects(tsa.EquipmentWorkRecords, db);
}
tsa.Facility = null;
tsa.Modifier = null;
if (tsa.PersonnelWorkRecords != null)
{
tsa.PersonnelWorkRecords = RemoveChildObjects(tsa.PersonnelWorkRecords, db);
}
tsa.ProjectActivity = null;
tsa.Structures = null;
tsa.Timesheet = null;
}
}
if (timesheet.TimesheetEquipment != null)
{
foreach (TimesheetEquipment te in timesheet.TimesheetEquipment)
{
te.Equipment = null;
te.Timesheet = null;
}
}
if (timesheet.EquipmentWorkdays != null)
{
timesheet.EquipmentWorkdays = RemoveChildObjects(timesheet.EquipmentWorkdays, true, db);
}
if (timesheet.TimesheetPersonnel != null)
{
foreach (TimesheetPersonnel tp in timesheet.TimesheetPersonnel)
{
tp.Personnel = null;
tp.PersonnelWorkday = null;
if (tp.PersonnelWorkday != null)
{
tp.PersonnelWorkday = RemoveChildObjects(tp.PersonnelWorkday, db);
}
tp.Timesheet = null;
}
}
if (timesheet.PersonnelWorkdays != null)
{
timesheet.PersonnelWorkdays = RemoveChildObjects(timesheet.PersonnelWorkdays, true, db);
}
return timesheet;
}
Debug of values before EF save
From my understanding anything an dbContex.ObjectNameHere.Local will be added/modified/deleted when a dbContext.Save() is called. (Depending on what the entity State is set too.) Here is what EF is trying to save before I call the save() and get an SQL FK exception.
Then I get the FK exception.
The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_PersonnelWorkRecords_TimesheetActivities". The conflict occurred
in database "VPMTEST_GC", table "dbo.TimesheetActivities", column
'TimesheetActivityID'. The statement has been terminated.
Notes
Please let me know if there is anything I can post to help describe my question. I have looked around google / SO for answers but so far no solid answers, it looks like EF can not determine the order of inserting objects unless the Domain model is setup differently? I am not able to change the structure of most objects as they are used by another system. I can attempt to change my EF call, I would prefer not to use Raw SQL as the objects are quite a bit more extensive then the simplified versions I have posted here.
Similar questions: Self referencing entity and insert order
In your RemoveChildObjects method I see the line...
tsa.Timesheet = null;
So, apparently your are setting the inverse navigation property of Timesheet.TimesheetActivities to null. Are you doing the same with PersonnelWorkRecord.TimesheetActivity and PersonnelWorkRecord.PersonnelWorkday, i.e. do you set those properties to null as well in the nested RemoveChildObjects methods?
This could be a problem because you have two different paths from Timesheet to PersonnelWorkRecord, namely:
Timesheet -> TimesheetActivities -> PersonnelWorkRecords
Timesheet -> PersonnelWorkdays -> PersonnelWorkRecords
When you call db.Timesheets.Add(timesheet) I believe EF will traverse each branch in the object graph one by one and determine on the path which related objects ("nodes") are dependent and which are principal in a relationship to determine the order of insertion. timesheet itself is principal for all its relationships, therefore it is clear that it must be inserted first. Then EF starts to iterate through one of the collections Timesheet.TimesheetActivities or Timesheet.PersonnelWorkdays. Which one comes first doesn't matter. Apparently EF starts with Timesheet.PersonnelWorkdays. (It would not solve the problem if it would start with Timesheet.TimesheetActivities, you would get the same exception, but with PersonnelWorkRecord.PersonnelWorkday instead of PersonnelWorkRecord.TimesheetActivity.) PersonnelWorkday is only dependent on Timesheet which is already inserted. So, PersonnelWorkday can be inserted as well.
Then EF continues traversing with PersonnelWorkday.PersonnelWorkRecords. With respect to the PersonnelWorkday dependency of PersonnelWorkRecord there is again no problem because the PersonnelWorkday has already been inserted before. But when EF encounters the TimesheetActivity dependency of PersonnelWorkRecord it will see that this TimesheetActivity is null (because you've set it to null). It assumes now that the dependency is described by the foreign key property TimesheetActivityID alone which must refer to an existing record. It inserts the PersonnelWorkRecord and this violates a foreign key constraint.
If PersonnelWorkRecord.TimesheetActivity is not null EF would detect that this object hasn't been inserted yet but it is the principal for PersonnelWorkRecord. So, it can determine that this TimesheetActivity must be inserted before the PersonnelWorkRecord.
I would hope that your code works if you don't set the inverse navigation properties to null - or at least not the two navigation properties in PersonnelWorkRecord. (Setting the other navigation properties like tsa.Creator, tsa.Facility, etc. to null should not be a problem because those related objects really already exist in the database and you have set the correct FK property values for those.)
This may no longer be valid, however is it an option to use a transaction and adding each child object individually?
Note:
I think Slauma's solution is more complete, however a transaction call may still be an option for others with similar issues.
I'm updating an existing entity by attaching it to my data context like this:
var updatedDocumentState = new AccDocumentState()
{
Id = accDocumentState.Id,
IsDocumentary = accDocumentState.IsDocumentary,
IsEditable = accDocumentState.IsEditable,
IsRecursive = accDocumentState.IsRecursive,
Title = accDocumentState.Title,
Reportable = accDocumentState.Reportable,
};
context.AccDocumentStates.Attach(updatedDocumentState);
context.ObjectStateManager.ChangeObjectState(updatedDocumentState, System.Data.EntityState.Modified);
flag = context.SaveChanges() > 0;
And this works, however after saving the attached entity, the properties of the existing entity which i didn't update, but i want to keep as they were, are overwritten and given null values. How can I attach my entity and keep the properties of the existing entity which i have not updated?
EF has an Object Data change tracker. Is enabled via proxies
Tracking changes in Poco entries
Essentially You/find Read the Object/Poco entity first.
Change only those properties you want. And save.
Only the changed properties are updated.
If you are not using autoDetectChnages
this.Configuration.AutoDetectChangesEnabled = false; ////<<<<<<<<< Default true
Then you would Call Detect Changes before Saving.
But either way the concept is based around a Read first to get entity.
Make the necessary changes and save.
Only the actually changes are sent back to Db.
eg:
var mypoco = Context.Set<TPoco>.Find(1);
myPoco.propertyXyz = "changed";
// normally not required by default, But incase your are not using tracking proxies , tell ef heads Up
// Context.Context.ChangeTracker.DetectChanges(); // uncomment when needed
Context.SaveChanged();
Only the actually changes are sent to DB.
Whilst the POST from Rameez is correct, it does not indicate why setting the whole entry as changed is desirable nor why do that ? Why link the State entry post from documentation ?
Context.Entry(poco).State = state; // why do this ? or the objectContext equivalent
This will result in an UPdate Set for all values going to Database on SaveChanges
Since ALL fields will be treated as changed. This is NOT a good way to use EF.
It is important to know about the auto detect changes in EF.
See Automatic detect changes
and Entity states and SaveChanges
As per msdn When you change the EntityState of an entity object entry to Modified, all the properties of the object are marked as modified, regardless of the current or original values. http://msdn.microsoft.com/en-us/library/system.data.objects.objectstatemanager.changeobjectstate.aspx
Hence I think all other properties get set to null as the object that you create will have other properties as null or their default values.
Below is the modified code.
var updatedDocumentState = context.AccDocumentStates.First(a => a.Id== accDocumentState.Id);
updatedDocumentState.IsDocumentary = accDocumentState.IsDocumentary,
updatedDocumentState.IsEditable = accDocumentState.IsEditable,
updatedDocumentState.IsRecursive = accDocumentState.IsRecursive,
updatedDocumentState.Title = accDocumentState.Title,
updatedDocumentState.Reportable = accDocumentState.Reportable,
flag = context.SaveChanges() > 0;
As a workaround to your problem, create a model for just the fields you are updating. Assuming this is a common scenario and warrants the extra model to avoid an extra call to the db.
With the new, minimized model, pointing to the same table, but with only the required properties, it will work as you want. Of course, nothing changed on the EF side, but it will only update the properties it knows about.
While I agree this is not how EF was designed, I too feel frustrated with the extra DB calls to do an update or delete. This solution helps with that.
Try this. Maybe works as you need:
var updatedDocumentState = context.AccDocumentStates.Find(accDocumentState.Id)
{
IsDocumentary = accDocumentState.IsDocumentary,
IsEditable = accDocumentState.IsEditable,
IsRecursive = accDocumentState.IsRecursive,
Title = accDocumentState.Title,
Reportable = accDocumentState.Reportable,
};
flag = context.SaveChanges() > 0;
I've had luck with the following. First I created an extension method to unset the IsModified flag for any property that is not in the set of properties that I want to restrict updates to:
public static void RestrictModifiedProps<ENT>(this DbContext context, ENT entity, IEnumerable<string> restrictedPropNames)
where ENT : class
{
//Grab the meta entry that knows whether the entity/properties have been updated
var entry = context.Entry(entity);
if (entry == null) return;
//loop over properties, only allow properties in the
// restrictedPropNames list to be modified
foreach (var propName in entry.CurrentValues.PropertyNames)
{
var prop = entry.Property(propName);
if (!prop.IsModified) continue;
prop.IsModified = restrictedPropNames.Any(O => O == propName);
}
}
In my case, I am accepting the entity's property values from a json post to an MVC action. So, I want to find out what properties were posted and created a (couple) extension methods for the controller:
public static JObject JsonPostData(this Controller cntrlr)
{
//ensure we're at the start of the input stream
Stream req = cntrlr.Request.InputStream;
req.Seek(0, SeekOrigin.Begin);
//read in any potential json
string json = d2s.SafeTrim(new StreamReader(req).ReadToEnd());
if (string.IsNullOrWhiteSpace(json)
|| !json.StartsWith("{")
|| !json.EndsWith("}"))
return null;
//try to deserialize it
return JsonConvert.DeserializeObject(json) as JObject;
}
public static IEnumerable<JProperty> JsonPostProperties(this Controller cntrlr)
{
JObject jObj = cntrlr.JsonPostData();
if (jObj == null) return null;
return jObj.Properties();
}
public static IEnumerable<string> JsonPostPropNames(this Controller cntrlr)
{
IEnumerable<JProperty> jProps = cntrlr.JsonPostProperties();
if (jProps == null) return null;
return jProps.Select(O => O.Name);
}
In the action, we get:
[HttpPost, ActionName("Edit")]
public virtual ActionResult Edit_Post(ENT obj)
{
...code...
Ctxt.Set<ENT>().Attach(obj);
Ctxt.Entry(obj).State = EntityState.Modified;
Ctxt.RestrictModifiedProps(obj, this.JsonPostPropNames());
...code...
}
If you are just excluding one or two properties, like say you never wanted to allow updates to the Title property (in your example), just unset IsModified on target properties after you set the object state to modified:
context.AccDocumentStates.Attach(updatedDocumentState);
context.ObjectStateManager.ChangeObjectState(updatedDocumentState, System.Data.EntityState.Modified);
context.Entry(updatedDocumentState).Property("Title").IsModified = false;
flag = context.SaveChanges() > 0;
Also FYI - Default MVC5 projects in VS use this line to set the object's modified property:
context.Entry(updatedDocumentState).State = System.Data.EntityState.Modified;