entity-framework-4.1 – 实体框架4.1更新外键属性的问题

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

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

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

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认为学位也受到影响?

谢谢.

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

我的表包含一个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进行了大量搜索,以及一般的谷歌搜索.我无法提出任何具体的解释.

谢谢.

点赞