【问题标题】:Self referencing table Unique and distinct key pair with Ef Core Fluent API自引用表 具有 Ef Core Fluent API 的唯一且不同的密钥对
【发布时间】:2021-01-24 01:22:12
【问题描述】:

我有一个用于自引用的多对多表,我希望有一个由两个外键组成的索引(或键)。 我还想避免相同的键重复和重新排序的键,例如

UserParentId xxx UserChildId

0                           1 => 好的

0                           2 => 好的

1                           1 => 不行

2                           0 => 不行,因为这个链接已经存在(见第二行)

最重要的是,我想在这个索引中使用无序提供的两个键进行搜索。 类似的东西

_dbContext.UserToUsers.Find(userId1, userId2)

不知道 userId1 是代表 UserParentId 还是 UserChildId

我已阅读此解决方案,这可能是一个很好的通用方法

模型应该保持 UserparentId 始终严格低于 UserChildId 和控制器都应该意识到这一点。

尽管如此,我仍然想知道类似的东西是否已经在 EF CORE 中实现。 Index() 或 HasAlternateKey() 似乎没有提供我想要的。有什么想法吗?

我的代码:

型号:

public class User
{
    public int Id { get; set; }

    public virtual ICollection<UserToUser> ChildrenUsers { get; set; }
    public virtual ICollection<UserToUser> ParentUsers { get; set; }
}
public class UserToUser
{
    public int Id { get; set; }
    public int UserParentId { get; set; }
    public int UserChildId { get; set; }

    public virtual User ChildUser { get; set; }
    public virtual User ParentUser { get; set; }
}

然后是我的 Fluent API 代码:

 modelBuilder.Entity<UserToUser>().HasOne(d => d.ChildUser)
            .WithMany(p => p.ParentUsers)
            .HasForeignKey(d => d.UserParentId); 

        modelBuilder.Entity<UserToUser>().HasOne(d => d.ParentUser)
            .WithMany(p => p.ChildrenUsers)
            .HasForeignKey(d => d.UserChildId);

        modelBuilder.Entity<UserToUser>()
            .HasAlternateKey(x => new {x.UserChildId, x.UserParentId});

【问题讨论】:

    标签: entity-framework-core foreign-keys self-reference key-pair


    【解决方案1】:

    关于使用 Find:

    DbSet 上的 Find 方法使用 primary 键值来尝试查找上下文跟踪的实体。如果在上下文中未找到实体,则将向数据库发送查询以在其中查找实体。如果在上下文或数据库中找不到实体,则返回 Null。

    Find 不支持通过备用键查找缓存,虽然尚未实现,但将来不再需要,因为查询缓存的备用方式将会发展,这意味着您可以编写一个名为 Find 的扩展方法来具体做什么你问。看看这个问题和相关的:DbSet.Find by alternate key or predicate(你不是第一个提出这种要求的人)

    因此,您要求 EF 在一个表上提供多个 PrimaryKeys,但还要强制一旦用户是另一个用户的 child,他们就不能是 em>parent 对于同一个用户,因此所有这些组合的值必须是唯一的:

    1. 身份证
    2. UserChildId、UserParentId
    3. UserParentId、UserChildId

    解决此问题的另一种方法是认识到,对于指定的 UserIds,您可以在每个 User 上使用 Find,特别是如果您仍然想要两个用户(因为链接表中没有其他信息,并且两个用户对象可以包含链接引用)

    var user1 = _dbContext.Users.Find(userId1);
    var user2 = _dbContext.Users.Find(userId2);
    var link = user1.ChildrenUsers.FirstOrDefault(x => x.UserChildId == userId2) 
            ?? user2.ChildrenUsers.FirstOrDefault(x => x.UserChildId == userId1)
    if (link != null)
    {
        // process when the link exists
    } 
    

    这将绕过本地缓存,但会完成这项工作:

    _dbContext.UserToUsers.Where(x => UserParentId == userId1 && UserChildId == userId2
                                      || UserParentId == userId2 && UserChildId == userId1);
    
    

    如果您只是进行存在性检查,则将Where 更改为Any,这样在服务器上运行同样有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-27
      • 1970-01-01
      • 2022-01-16
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多