Here is a simple entity:
public class Customer : Entity
{
public virtual Location Location { get; set; }
}
Now suppose we have a customer already:
var customer = new Customer() {Location = new Location("China")};
and now we want to update his location:
var customer = context.Customers.First(x => x.Location.Country == "China");
customer.Location = new Location("America");
context.SaveChanges();
and now when I look at the database, the location record "China" has not been deleted: the database now has two location records association with one customer record.
The reason for this issue is that I'm using virtual keyword on the Customer.Location property, and when I query the customer entity from database I didn't use Include method to load the Location property, and I also did not use any accesses to lazy load it. So EF can't track and know the China
Location entity should be deleted.
I think the approach I used to the update virtual property is in line with intuition. I want update a property, then just use a update instruction "entity.xxx=...", add being forced to use some access of the property or method call while loading "entity.xxx" is not intuitive.
So I am looking for some better way to replace an entity's virtual property directly. Any suggestions?
Solutions update
I'm find two way to do this easy,
First you can use Identifying relation(recommend).
Another way you can Use ObjectContext.DeleteObject method, below is the example code:
public static class EFCollectionHelper
{
public static void UpdateCollection<T, TValue>(this T target,
Expression<Func<T, IEnumerable<TValue>>> memberLamda, TValue value)where T : Entity
{
var memberSelectorExpression = (MemberExpression)memberLamda.Body;
var property = (PropertyInfo)memberSelectorExpression.Member;
var oldCollection = memberLamda.Compile()(target);
oldCollection.ClearUp();
property.SetValue(target, value, null);
}
public static void ClearUp<T>(this IEnumerable<T> collection)
{
//Convert your DbContext to IObjectContextAdapter
var objContext = ((IObjectContextAdapter) Program.DbContext).ObjectContext;
for (int i = 0; i < collection.Count(); i++)
{
objContext.DeleteObject(collection.ElementAt(i));
}
}
}
And then you can simply write the code like:
customer.UpdateCollection(x => x.Locations, null);