1

I went through this answer, but it still gave me the same exception. My DbContext has Configuration.AudoDetectChangesEnabled = false and Configuration.LazyLoadingEnabled = true, in case that makes a difference. For a simple example, consider the following:

public class Employee {
    public int Id {get;set;}
    public int TitleId {get;set;}

    [ForeignKey(nameof(Employee.TitleId))]
    public virtual Title Title{get;set;}
}

Query is done with Context.Set<Employee>().Include(nameof(Employee.Title)). In my case, I have an existing Employee with an existing Title. I've updated my entity with a new TitleId, one that already exists in the database. Then, I update the EntityState to EntityState.Modified and call SaveChanges(). This gives the following Exception:

A referential integrity constraint violation occurred: The property value(s) of 'Employee.TitleId' on one end of a relationship do not match the property value(s) of 'Title.Id' on the other end.

Okay, so that should be due to a mismatch between the foreign key id and the navigation property. So then I set Title to null prior to setting EntityState. Still the same issue.

Next, I've tried detaching the entity prior to setting EntityState.Modified. Now, saving the entity works, but when I try to load it again, I get a NullReferenceException on the navigation property.

What's the proper way to do this?

Lunyx
  • 3,164
  • 6
  • 30
  • 46

1 Answers1

0

Do not try to update only the Id property, update the Title entity on the employee instead and the Id property should follow. So fetch the existing title and student from the db and set the title of the student to the title you fetched from the db.

Other things i would do differently is using System.Data.Entity and use include with a lambda expression instead to make it more explicit and failsafe. Like so:

 Context.Set<Employee>().Include(x => x.Title);

And if i read things right your ForeignKey annotation is obsolote in this case since EF conventions will map to the same name anyway. I also think it is a bit of a code smell to have mapping information on the entity. Use fluent api instead. http://www.entityframeworktutorial.net/code-first/foreignkey-dataannotations-attribute-in-code-first.aspx

  • Performing a db call just to update an entity sounds like the wrong way to approach this problem. If I already have the foreign key id, I shouldn't need to do another EF call to get the actual entity itself. Having a UI Model is a good example of how I can have the Id, but not the entity. I already have a different way to Include, but this was merely an example. EF convention by default maps `Title` to `Title_Id`, not `TitleId`, so I don't think it's obsolete. I disagree that Fluent API is the better solution. No reason to maintain two locations instead of one. – Lunyx Nov 07 '17 at 21:09
  • Have you tried setting the AutoDetectChanges to true before doing this update? Then you should not need to set the EntityState flags either. Did not mean have 2 solutions, have only 1 and use fluent api. Mainly because then you have mapping information in the DA layer which is a more logic place to put it. But both works and it all depends on the size of the solution really. I was schooled in DDD and then mapping info was forbidden in our domain project which is also why i am against having a foreign key property at all. The extra db call is worth it if you ask me. Hope this helps. – Mathias Marin Nov 08 '17 at 12:38
  • AutoDetectChanges does fix the issue, but it also comes with significant performance issues given the data set that I'm working with. In the end, I came up with a workaround where I overrode SaveChanges() and added code to detect if any foreign key relationships have changed, and if so, call DetectChanges(). This lets me keep all other updates that don't involve FK relations to still be reasonably fast and adding some overhead on saving ones that do involve FKs. – Lunyx Nov 08 '17 at 14:35