I have a problem with EF6 when using "disconnected" contexts. I'm using database first and have modelled a many-to-many relationship this way (there is a junction table behind the relation shown, with two FKs, which together make up the composite PK for the junction table. No other columns in that junction table):
Since I want to use EF in a disconnected way (short-lived contexts, ready for a web API) I have also implemented the "painting the state" method from Julie Lerman and Rowan Millers book on the DbContext. Specifically the method they describe in chapter 4 of the book, "Recording original values" (p.102 and forward). This is my ApplyChanges method:
public static void ApplyChangesInGraph<TEntity>(TEntity root) where TEntity : class, IObjectWithState
{
using (var context = new NovaEntities2())
{
context.Set<TEntity>().Add(root);
foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.State);
if (stateInfo.State == State.Unchanged)
{
ApplyPropertyChanges(entry.OriginalValues, stateInfo.OriginalValues);
}
}
context.SaveChanges();
}
}
With this in place, I get an exception with the following test:
[Fact]
public void ShouldNotResultInAnInsertOfPlaceOfEmployment()
{
ResetDbToKnownState();
Employee employee;
using (var context = new NovaEntities2())
{
employee = context.Employees
//.Include(e => e.PlacesOfEmployment) // If enabled, an exception is thrown.
.First();
}
employee.Name = "A new name";
NovaEntities2.ApplyChangesInGraph(employee);
}
If I enable the .Include above, the following exception occurs:
System.Data.Entity.Infrastructure.DbUpdateExceptionAn error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.
InnerException: System.Data.SqlClient.SqlExceptionViolation of PRIMARY KEY constraint 'PK_EmployeePlaceOfEmployment'. Cannot insert duplicate key in object 'dbo.EmployeePlaceOfEmployment'. The duplicate key value is (140828, 14). Ie. with the .Include added above, EF issues an update of the Employee (fine) AND an insert of the already existing PlaceOfEmployment (not so fine) for the simple case above, where I only try to update the name of the Employee.
I cannot for the life of me figure out why an INSERT occurs here, violating the primary key. I've tried stepping through the foreach in the ApplyChanges method, and verified that all entity states are being set correctly. Indeed, on the first iteration, the Employee entity starts out as Added, and ends up in the Modified state. Next, the eager loaded PlaceOfEmployment entity is being processed and it starts out as Added and ends up in the Unchanged state. However, an INSERT is still being generated, resulting in the exception.
From SQL profiler: