EF 4.1, POCO: Reference type properties are not updated in case AutoDetectChanges=false
EF 4.1, POCO: I turned off AutoDetectChanges (Configuration.AutoDetectChangesEnabled = false) to speed up data update. Then I run Add or Attach with entity state changed to EntityState.Modified. All this causes references to other objects not being updated in database. However all scalar properties are updated successfully.
Profiler shown EF generates SQL update operation for every scalar property, but not for reference type, though I really changed its value in my code. This issue reproduced for every type of ent开发者_如何学Pythonity in my model.
Add operation or Attach with EntityState.Added both work fine. If I turn AutoDetectChanges back on, everything works fine as expected for updated records too.
Help me please to figure out what's wrong. I can not find any good comprehensive documentation on EF's Detect Changes.
UPDATE
I was asked to put some example of code to reproduce the issue. Domain:
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public virtual string City { get; set; }
}
DataContext:
public class DataContext : DbContext
{
public DbSet<Client> Clients { get; set; }
public DbSet<Address> Address { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Client>().HasOptional(c => c.Address);
}
}
Add one record to Clint table and one to Address. Point Client to the Address. Then run the following code:
using (var cntx = new DataContext())
{
cntx.Configuration.AutoDetectChangesEnabled = false; // Reason of problem
var client = cntx.Clients.First();
client.Name = "Anna"; // This property will be updated
client.Address = null; // This property will not be updated
cntx.Clients.Attach(client);
cntx.Entry(client).State = EntityState.Modified;
cntx.SaveChanges();
}
This code does generates SQL script like this:
update [dbo].[Clients] set [Name] = 'Anna'
where ([Id] = 1)
Set AutoDetectChangesEnabled to true and run the code again, this time everything alright:
update [dbo].[Clients]
set [Name] = 'Anna', [Address_Id] = null
where (([Id] = 1) and [Address_Id]=1)
Note it does not matter if you change Address's value from specific value to null, or back to specific value, or one concrete value to other concrete value, any change is not tracked while AutoDetectChanges=false. Seems like EF bug.
See Change Tracking on MSDN
Well, I found out the way to set Reference property values that works even with AutoDetectChangesEnabled=false:
cntx.Entry(client).Reference(c => c.Address).CurrentValue = null;
However I definitely do not like it. 1) Code looks ugly; 2) You have to have access to context to make it work, which is not my case, I'd like this property being set outside of repository which only has access to DbContext. Is any other simpler way to let EF know the property value is changed?
Updated: Ok, I found simpler workaround: just run cntx.ChangeTracker.DetectChanges() before running cntx.SaveChanges(). It helps EF generate correct SQL update script
精彩评论