实体框架多对多自我关系和乐观并发控制

Far*_*ori 9 c# entity-framework optimistic-concurrency

我有一个拥有多对多自我关系的实体.作为一个例子考虑这个实体:

public class User
{
    public int ID { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<User> Friends { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

以下是我配置映射的方法:

HasMany(t => t.Friends).WithMany()
    .Map(m => { 
        m.MapLeftKey("UserID");
        m.MapRightKey("FriendID");
        m.ToTable("UserFriends");
        });
Run Code Online (Sandbox Code Playgroud)

由于此关系现在由EF管理,我实际上无法访问UserFriends DbSet我的代码并且无法处理对它的并发访问.为了使这个组合处理并发访问(添加/删除),我是否需要自己处理多对多关系,然后添加一个[Timestamp]列或者有没有办法告诉EF自己同时处理它?就像模型构建器中的配置一样.

编辑:我正在使用EF 6,目前如果实体上有并发操作(例如,尝试删除当前未在数据库上退出的朋友),我收到以下错误消息,并且DbUpdateException:

保存不公开其关系的外键属性的实体时发生错误.EntityEntries属性将返回null,因为无法将单个实体标识为异常的来源.通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常.有关详细信息,请参阅InnerException.

mr1*_*100 1

虽然 UserFriends 表上没有 rowversion 列,但 EF 仍然能够识别出 DbContext.SaveChanges 失败的原因是多对多关系中的并发问题。在这种情况下,ef 会抛出 OptimisticConcurrencyException 异常,并且使用 DbUpdateException 进行不透明处理。使用以下代码来捕获它:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能无法将当前的 Fluent api 配置为自动包含在 UserFriends 表 rowversion 列中,但是生成迁移后,您可以手动添加到 UserFriends CreateTable 语句 rowversion 列的定义:

CreateTable(
    "dbo.UserFriends",
    c => new{
        RowVersion = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
        // other columns definitions
    });
Run Code Online (Sandbox Code Playgroud)

但是,当多对多关系中发生并发问题时,这不会改变 DbContext 的行为。