我正在开发一个在断开连接的环境中使用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认为学位也受到影响?
谢谢。
答案 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进行了大量搜索,以及一般的谷歌搜索。我无法提出任何具体的解释。
谢谢。