我有一个拥有多对多自我关系的实体。作为一个例子,考虑这个实体:
public class User
{
public int ID { get; set; }
public string UserName { get; set; }
public virtual ICollection<User> Friends { get; set; }
}
以下是我配置映射的方法:
HasMany(t => t.Friends).WithMany()
.Map(m => {
m.MapLeftKey("UserID");
m.MapRightKey("FriendID");
m.ToTable("UserFriends");
});
由于此关系现在由EF管理,因此我无法在代码中访问UserFriends
DbSet
,无法处理对其的并发访问。
为了使这个组合处理并发访问(添加/删除),我是否需要自己处理多对多关系,然后添加[Timestamp]
列,或者有一种方法告诉EF同时处理这个本身?与模型构建器中的配置类似。
编辑:我正在使用EF 6,目前如果实体上有并发操作(例如,尝试删除当前不在数据库上退出的朋友),我会收到以下错误消息, DbUpdateException
:
保存不公开外键的实体时发生错误 他们关系的属性。 EntityEntries属性将 返回null,因为无法将单个实体标识为源 例外。可以在保存时处理异常 通过在实体类型中公开外键属性更容易。看到 InnerException以获取详细信息。
答案 0 :(得分:3)
乐观并发不适用于此。
联结表永远不会更新。其记录可以添加或删除。这意味着没有需要rowversion的CRUD操作。
事实上,并发性相当容易:
因此,归结为处理异常并将其转换为可理解的用户反馈。所有这些情况也必须在更新(和乐观并发)确实发挥作用的情况下处理。
答案 1 :(得分:1)
虽然UserFriends表上没有rowversion列,但EF仍然能够识别DbContext.SaveChanges失败的原因是多对多关系时的并发问题。在这种情况下,ef会抛出使用DbUpdateException的OptimisticConcurrencyException异常。使用以下代码来捕获它:
try
{
context.SaveChanges();
}
catch (DbUpdateException ex)
{
if(ex.InnerException is OptimisticConcurrencyException)
{
// If you are here then there was concurrency problem in many-to-many relationship
}
}
您可能无法将当前流畅的api配置为自动包含在UserFriends表rowversion列中,但是在生成迁移后,您可以手动添加到rowversion列的UserFriends CreateTable语句定义中:
CreateTable(
"dbo.UserFriends",
c => new{
RowVersion = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
// other columns definitions
});
然而,当多对多关系出现并发问题时,这不会改变DbContext行为。