EF 4.1,POCO:如果AutoDetectChanges = false,则不更新引用类型属性

时间:2011-08-16 20:45:46

标签: entity-framework entity-framework-4.1 poco savechanges

EF 4.1,POCO:我关闭了 AutoDetectChanges Configuration.AutoDetectChangesEnabled = false )以加速数据更新。然后我运行添加附加,将实体状态更改为 EntityState.Modified 。所有这些都会导致引用其他未在数据库中更新的对象。但是,所有标量属性都会成功更新。

Profiler显示EF为每个标量属性生成SQL更新操作,但不为引用类型生成SQL更新操作,尽管我在代码中确实更改了它的值。这个问题在我的模型中为每种类型的实体重现。

使用 EntityState.Added

添加操作或附加都可以正常工作。如果我重新打开 AutoDetectChanges ,一切都正常,因为更新的记录也是如此。

请帮我弄清楚是什么问题。我找不到关于EF检测变化的任何好的综合文档。

更新

我被要求提供一些代码示例来重现这个问题。域:

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);
    }
}

将一条记录添加到Clint表,将一条记录添加到Address。将客户端指向地址。然后运行以下代码:

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();
}

此代码确实生成如下SQL脚本:

update [dbo].[Clients] set [Name] = 'Anna'
where ([Id] = 1)

将AutoDetectChangesEnabled设置为true并再次运行代码,这次一切都好了:

update [dbo].[Clients]
set [Name] = 'Anna', [Address_Id] = null
where (([Id] = 1) and [Address_Id]=1)

注意,如果将Address的值从特定值更改为null,或者返回到特定值,或者将一个具体值更改为其他具体值,则在AutoDetectChanges = false时不会跟踪任何更改。好像是EF bug。

2 个答案:

答案 0 :(得分:2)

答案 1 :(得分:2)

好吧,我找到了设置Reference属性值的方法,即使使用AutoDetectChangesEnabled = false也是如此:

cntx.Entry(client).Reference(c => c.Address).CurrentValue = null;

但我绝对不喜欢它。 1)代码看起来很难看; 2)您必须能够访问上下文以使其工作,这不是我的情况,我希望此属性设置在只能访问DbContext的存储库之外。有没有其他更简单的方法让EF知道属性值被改变了?

已更新:好的,我发现更简单的解决方法:在运行cntx.SaveChanges()之前运行cntx.ChangeTracker.DetectChanges()。它有助于EF生成正确的SQL更新脚本<​​/ p>