Reputation: 8323
I have a POCO class (OPERATION
) that is used as an Entity Framework entity. This class has a navigation property (OP
) and a foreign key into the same related entity (OP_ID
).
In a method, I get an OPERATION
and on this OPERATION
the OP_ID
and OP
are both null
. When I set the OP_ID
to a valid value for this foreign key, the OP
navigation property remains null
. When I explicitly detect changes in the context, the OP
navigation property is now assigned with the correct value.
Sample code
public bool UpdateOperation(operationID)
{
IQueryable<OPERATION> operations = from o in base.ctx.OPERATION
select o;
OPERATION operation = operations
.Where(o => o.OPERATION_ID == operationID)
.Include("OP")
.FirstOrDefault();
if (operation != null)
{
operation.OP_ID = opId;
}
// operation.OP is null here
operation.GetContext().ChangeTracker.DetectChanges();
// operation.OP is populated here
}
I have confirmed that the operation
is, in fact, a dynamic proxy. For what it's worth, once I detect changes, operation.OP
also becomes a dynamic proxy. However, even then, assigning a different value to operation.OP_ID
still requires an explicit DetectChanges()
call in order to update the value of operation.OP
.
Update
In response to the comment from @ErikPhilips, the documentation here seems to imply that this should happen. Specifically:
The following examples show how to use the foreign key properties and navigation properties to associate the related objects. With foreign key associations, you can use either method to change, create, or modify relationships. With independent associations, you cannot use the foreign key property.
By assigning a new value to a foreign key property, as in the following example.
course.DepartmentID = newCourse.DepartmentID;
...
When you change the relationship of the objects attached to the context by using one of the methods described above, Entity Framework needs to keep foreign keys, references, and collections in sync. Entity Framework automatically manages this synchronization (also known as relationship fix-up) for the POCO entities with proxies.
If you are using POCO entities without proxies, you must make sure that the DetectChanges method is called to synchronize the related objects in the context.
Some additional context may be useful, as well. This is a legacy application that used to work directly with an ObjectContext
instead of a DbContext
, though even then using EF 6. We are now migrating to the DbContext
API. This particular code, without any modifications, used to demonstrate the behavior I'm expecting. Specifically, when OP_ID
is assigned, I can see in the debugger that the OP
property is automatically populated to point to the correct OPERATION
.
Upvotes: 0
Views: 606
Reputation: 8323
In the end, I was doing exactly what the documentation described. I was
assigning a new value to a foreign key property.
Yes, Entity Framework does manage this in fix-up. And yes, the documentation does state this.
It turns out, though, that the egg is ultimately on my face. I had checked the classes generated from my T4 template, and seen that all navigation properties were marked virtual
. I had not checked thoroughly enough to note that the foreign key properties were not marked virtual
, however. It appears that this is the default behavior of the EF-provided T4 template used when working model- or database-first. I've addressed this by changing this line in the CodeStringGenerator.Property()
method in the T4 template
Accessibility.ForProperty(edmProperty)
to
AccessibilityAndVirtual(Accessibility.ForProperty(edmProperty))
In the end, as usual, following the documentation (here, the requirements for EF change tracking on POCOs) often results in dependent code behaving as it is documented. Shame on me.
Upvotes: 1