1

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

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

添加操作或Attach with EntityState.Added都可以正常工作。如果我重新打开AutoDetectChanges,对于更新的记录,一切都会按预期正常工作。

请帮助我找出问题所在。我找不到任何关于 EF 的 Detect Changes 的全面文档。

更新

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

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

数据上下文:

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 错误。

4

2 回答 2

2

请参阅MSDN 上的更改跟踪

于 2011-08-16T20:54:54.370 回答
2

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

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

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

更新:好的,我找到了更简单的解决方法:在运行 cntx.SaveChanges() 之前运行 cntx.ChangeTracker.DetectChanges()。它帮助 EF 生成正确的 SQL 更新脚本

于 2011-08-17T22:36:29.247 回答