簡體   English   中英

自引用表與 Ef Core Fluent 的唯一且不同的密鑰對 API

[英]Self referencing table Unique and distinct key pair with Ef Core Fluent API

我有一個多對多的自引用表,我希望有一個由兩個外鍵組成的索引(或鍵)。 我還想避免相同的鍵重復和重新排序的鍵,比如

UserParentId xxx UserChildId

0 1 => 好的

0 2 => 好的

1 1 => 不行

2 0 => 不行,因為這個鏈接已經存在(見第二行)

最重要的是,我想使用無序提供的兩個鍵在此索引中進行搜索。 就像是

_dbContext.UserToUsers.Find(userId1, userId2)

不知道 userId1 代表UserParentId還是UserChildId

我讀過這個解決方案,它可能是一個很好的通用方法

model 應該讓UserparentId始終嚴格低於UserChildId ,控制器應該都知道這一點。

盡管如此,我仍然想知道是否已經在 EF CORE 中實現了類似的功能。 Index() 或 HasAlternateKey() 似乎沒有提供我想要的。 任何的想法?

我的代碼:

Model:

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 方法使用鍵值來嘗試查找上下文跟蹤的實體。 如果在上下文中找不到該實體,則將向數據庫發送查詢以在其中查找該實體。 如果在上下文或數據庫中找不到該實體,則返回 Null。

Find不支持通過替代鍵進行緩存查找,盡管尚未實現,但在未來將不再需要,因為查詢緩存的替代方法將會發展,這意味着您可以編寫一個名為Find的擴展方法來專門執行您的要求。 看看這個問題和與之相關的問題: DbSet.Find by alternate key or predicate (你不是第一個提出這種請求的人)

因此,您要求 EF 在表中提供多個PrimaryKeys ,但也強制執行一旦用戶是另一個用戶的孩子,他們就不能成為同一用戶的級,因此所有這些組合的值必須是唯一的:

  1. ID
  2. UserChildId, UserParentId
  3. UserParentId, UserChildId

解決這個問題的另一種方法是認識到對於指定的UserId您可以在每個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 ,這樣在服務器上運行同樣有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM