I've searched... I promise. The closest I came to an answer is a post where EF self tracking entities are used and I don't understand how to make it apply to my situation.
In my case, I have an existing record where I want to change a value from an int to a NULL.
Table Pseudocode:
PICKLIST_VALUE
Picklist ID (int, PK, Identity, NOT NULL)
PicklistValue (String, NOT NULL)
PERSON
Person_ID (int, PK,Identity, NOT NULL)
Person_Name (varchar(100), NOT NULL)
Person_Prefix (int, FK, NULL)
Person_Suffix (int, FK, NULL)
FOREIGN KEY (Person_Prefix) REFERENCES PICKLIST_VALUES.Picklist_ID
FOREIGN KEY (Person_Suffix) REFERENCES PICKLIST_VALUES.Picklist_ID
I am using EF6, DB first... With a DAL based on Magnus Montin's post at https://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/
In my code I have POCO definitions for each entity (table). A Person can have a prefix (Mr., Mrs., etc.) and a Person can have a suffix (Jr., Sr., etc.) If I accidentally set a suffix and then realize that it's incorrect, I want to be able to remove the suffix:
someperson.Person_Suffix = null; // Set FK property to null
someperson.PICKLIST_VALUE = null; // Set navigation property to null
someperson.EntityState = EntityStates.Modified;
DAL.UpdatePerson(someperson);
The UpdatePerson method resolves to this bit based on the DAL article:
public virtual void Update(params T[] items)
{
using (var context = new Entities())
{
DbSet<T> dbSet = context.Set<T>();
foreach (T item in items)
{
dbSet.Add(item);
foreach (DbEntityEntry<IEntity> entry in context.ChangeTracker.Entries<IEntity>())
{
IEntity entity = entry.Entity;
entry.State = GetEntityState(entity.EntityState);
}
}
context.SaveChanges();
}
}
protected static System.Data.Entity.EntityState GetEntityState(CB.DomainModel.EntityState entityState)
{
switch (entityState)
{
case DomainModel.EntityState.Unchanged:
return System.Data.Entity.EntityState.Unchanged;
case DomainModel.EntityState.Added:
return System.Data.Entity.EntityState.Added;
case DomainModel.EntityState.Modified:
return System.Data.Entity.EntityState.Modified;
case DomainModel.EntityState.Deleted:
return System.Data.Entity.EntityState.Deleted;
default:
return System.Data.Entity.EntityState.Detached;
}
}
I don't know enough of what's going on under the covers of the EF stuff and what the .edmx and T4 template code does. If I did, I could probably figure this out. But if I change the values from one int to another, the changes are persisted to the database after this call. But if I null the values, as in this example, to "clear" the foreign key reference, the original value comes back.
It must have something to do with the way the object registers with the ChangeTracker once it's added to the dbSet. Prior to that, it's just a plain old object.
So my question is why is the ChangeTracker (or whatever bit of auto-generated code) allowing the FK to change from one int value to another, but it won't persist the null? And how do I "fix" it or work around the issue?
Thanks. J
UPDATE:
The key is definitely nullable. Both in the DB and in the class definition. The link to the other post seems to be a different scenario... They want to automatically null the foreign key when the foreign entity is deleted. (I will take a closer look, just to be sure there isn't an answer there, but it seems to be a different issue.) Just for fun I created a new object and copied the properties over, with the exception of the nav properties and set the FK property I want to remove to null and that did work. The null FK was persisted, and both the nav prop and the foreign key prop were null. So it has something to do with the change tracker and how it is maintaining a reference to the entity object, despite all the POCO-ness of it. So, at the very least, I have a work-around. But I would like to understand what's actually happening and how to address it.
SOLUTION:
I just discovered, this morning, that a change I made to the T4 template must have been over-ridden, at some point, and I lost a line setting ProxyCreationEnabled to false for the DBContext... Once I realized that and put the fix in, I was able to persist the changes properly. So, in effect, I was fighting something in the change tracker since it was creating the dynamic proxies for the entities retrieved from the DB. (I think.)