实体框架4.1更新外键属性的问题

时间:2011-08-24 16:28:21

标签: entity-framework-4.1

我正在开发一个在断开连接的环境中使用Entity Framework 4.1和DbContext API的应用程序。我有两个基本实体,人和学位。学位与人有非强制性的一对多关系。

当我将Person实体上的DegreeId属性更新为其他值时,会出现此问题。保存更改时,EF会在实际Degree表上生成Update语句。当两个或多个用户正在使用该应用程序时,这反过来会导致并发错误违规。我在使用SQL事件探查器时能够找到问题。我已经使用Fluent API尝试了几种配置变体,但似乎没有任何东西可以抑制Degree表上的其他Update语句。

以下是我的实体:

public partial class Person
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public Nullable<int> DegreeId { get; set; }

        public Degree Degree { get; set; }
    }

public partial class Degree 
    {
        public int DegreeId { get; set; }
        public string Name { get; set; }
    }

在我的Repository类中,我正在加载Person对象图:

public override Person GetById(int id)
   {
         return DataContext.People
                    .Include(d => d.Degree)
                    .FirstOrDefault(x => x.PersonId == id);
   }

在我的服务层中,我正在获取人员记录,然后将DegreeId属性更新为特定值。注意:UnitOfWork.Commit方法在DbContext上公开SaveChanges。

using (var unitOfWork = IoC.Resolve<IUnitOfWork>())
  {
        var personRepository = new PersonRepository(unitOfWork);
        var person = personRepository.GetById(240);
        person.DegreeId = 1;
        personRepository.Update(person);
        unitOfWork.Commit();
  }

我的存储库更新方法附加人员实体并将实体状态标记为已修改:

var state = DataContext.Entry(entity).State;
dbSet.Attach(entity);
DataContext.Entry(entity).State = EntityState.Modified; 

以下是Profiler会话中的SQL语句:

exec sp_executesql N'declare @p int
update [Client].[Degree]
set @p = 0
where (([DegreeId] = @0) and ([RowVersion] = @1))
select [RowVersion]
from [Client].[Degree]
where @@ROWCOUNT > 0 and [DegreeId] = @0',N'@0 int,
@1 binary(8)',@0=1,@1=0x0000000000004469

有谁知道如何阻止EF将此更新语句发送到SQL Server?我的实体配置中是否有明显的因素导致EF认为学位也受到影响?

谢谢。

1 个答案:

答案 0 :(得分:2)

我能够找到这个问题的原因并防止它发生,但我无法解释它为什么会发生。

我的表包含一个TimeStamp列和我的实体的基类中的相应属性。 我没有在原始问题中显示基类,因为它只包含RowVersion和其他审计属性,我认为这些属性无关紧要。 有人会认为我会通过不知道任何有关实体框架的内容来学习。

这是Degree实体的基类定义:

public abstract class EntityBase : ValidableObject, IEntityBase
{
    public virtual byte[] RowVersion { get; protected set; }
    public virtual DateTime? CreateDate { get; set; }
    public virtual string CreateUser { get; set; }
    public virtual DateTime? ModifyDate { get; set; }
    public virtual string ModifyUser { get; set; }
}

以下是Degree实体的上下文模型配置:

internal class DegreeConfiguration : EntityTypeConfiguration<Degree>
    {
        internal DegreeConfiguration()
            : base()
        {
            ToTable("Degree", "dbo");
            Property(x => x.RowVersion).IsRowVersion();
        }
    }

由于我的应用程序需求,我必须使用Include方法加载Person实体以急切加载Degree实体,因此对象图是 消费者请求实体时完全填充。

return ctx.People.Include(p => p.Degree).Where(x => x.PersonId == id).First();

当修改Person对象的DegreeId属性并将其附加到Context时,将生成以下Update语句 在调用SaveChanges()时:

exec sp_executesql N'declare @p int
update [dbo].[Degree]
set @p = 0
where (([DegreeId] = @0) and ([RowVersion] = @1))
select [RowVersion]
from [dbo].[Degree]
where @@ROWCOUNT > 0 and [DegreeId] = @0',N'@0 int,
@1 binary(8)',@0=2,@1=0x00000000000007DF

即使我不是故意更新Degree实体并且当两个或多个用户同时使用该应用程序时造成严重破坏,这种情况仍然存在。

要禁止在Degree导航属性上生成Update语句,我注释掉了对模型配置的并发检查:

internal class DegreeConfiguration : EntityTypeConfiguration<Degree>
    {
        internal DegreeConfiguration()
            : base()
        {
            ToTable("Degree", "dbo");
            //Property(x => x.RowVersion).IsRowVersion();
        }
    }

重新执行该过程后,EF不再生成有问题的Update语句。

我在MS网站上为EF 4.1进行了大量搜索,以及一般的谷歌搜索。我无法提出任何具体的解释。

谢谢。