自引用表,具有Ef Core Fluent API的唯一和独特密钥对

问题描述

我有一个用于自引用的多对多表,我想为其提供一个由两个外键组成的索引(或键)。 我也想避免相同的按键重复和像

UserParentId xxx UserChildId

0

0

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});

解决方法

关于使用“查找”:

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

Find不支持通过备用键进行缓存查找,尽管尚未实现,但将来将不再需要查询缓存的替代方法,这意味着您可以编写名为{{ 1}}专门执行您的要求。看看这个问题及其相关的问题:DbSet.Find by alternate key or predicate(您不是第一个提出这种请求的人)

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

  1. 编号
  2. UserChildId,UserParentId
  3. UserParentId,UserChildId

解决此问题的另一种方法是,对于指定的Find,您可以在每个UserId上使用“查找”,尤其是如果您仍然希望两个用户都使用(因为链接表中没有其他信息) ,并且两个用户对象都可以包含链接引用)

User

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

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,这将与在服务器上运行一样有效。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...