我正在使用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进行了大量搜索,以及一般的谷歌搜索.我无法提出任何具体的解释.
谢谢.