簡體   English   中英

EF Core 中是否有可能需要單向導航屬性?

[英]Is it possible in EF Core to make a one-way navigation property required?

我正在開發一個基本的群聊系統,為此我創建了這些類:

public class Role
{
    public Guid Id { get; set; };
    public string Username { get; set; }
}

public class Message
{
    public Guid Id { get; set; };
    public Role Author { get; set; }
    public Conversation Conversation { get; set; }
    public DateTime Date { get; set; }
    public string Text { get; set; }
}

public class Conversation
{
    public Guid Id { get; set; };
    public IList<ConversationParticipant> ConversationParticipants { get; set; };
    public IList<Message> Messages { get; set; };
}

public class ConversationParticipant
{
    public Conversation Conversation { get; set; }
    public Role Role { get; set; }
}

我們在遷移中使用 EF Core 3.1 Code-First。

我正在尋找一種使Message.Author成為必需屬性的方法,這應該導致表Message中的列被創建為AuthorId NOT NULL

我試過了:

public static void Map(this EntityTypeBuilder<Message> builder)
{
    builder.HasOne(m => m.Author);
}

由於這是使用 Add-Migration 和 Update-Database 應用的,因此會創建數據庫列AuthorId ,但允許使用NULL

似乎沒有我可以在 HasOne() 之后添加的方法IsRequired() HasOne()

我也試過:

public static void Map(this EntityTypeBuilder<Message> builder)
{
    builder.Property(m => m.Author).IsRequired();
}

但這沒有說

屬性“Message.Author”屬於“角色”類型,當前數據庫提供程序不支持。 更改屬性 CLR 類型或使用“[NotMapped]”屬性或使用“OnModelCreating”中的“EntityTypeBuilder.Ignore”忽略該屬性。

執行.HasOne(...)后跟 .Property( .Property(...).IsRequired()也不起作用:

“作者”不能用作實體類型“消息”的屬性,因為它被配置為導航。

我設法通過以下方式使Message.Conversation成為必需:

public static void Map(this EntityTypeBuilder<Conversation> builder)
{
    builder.HasMany(c => c.Messages)       // A conversation can have many messages
           .WithOne(e => e.Conversation)   // Each message belongs to at most 1 conversation
           .IsRequired();                  // A message always has a conversation
}

但是,我不想讓Role知道消息,因為我永遠不想直接從角色中檢索消息(這將通過對話和參與者發生)。

我的最終問題是:有沒有一種方法可以使Message.Author成為必需(非空),而無需將MessageRoleRole中的 Messages 屬性以完全一對多的關系鏈接在一起?

Role的外鍵添加到Message然后要求該屬性不是 null 怎么樣? 就像是:

// MessageConfiguration.cs
builder.Property(b => b.RoleId).IsRequired()

雖然@Ben Sampica 的回答很有幫助並讓我到達了我需要的地方,但@Ivan Stoev 的評論提供了細節和清晰度,讓我認為更全面的答案會很有用。

有多種方法可以在生成的表中使外鍵列成為必需(NOT NULL)。

  1. 最簡單的是將[Required]放在導航屬性上:

     public class Message { //... [Required] public Role Author { get; set; } //... }

    這將導致 EF 創建Guid類型的影子屬性AuthorId ,因為 Message.Author 是 Role 並且 Role.Id 是 Guid 類型。 在 SQL 服務器的情況下,這會導致UNIQUEIDENTIFIER NOT NULL

    如果省略[Required]則 EF 將使用Guid? ,這會導致UNIQUEIDENTIFIER NULL ,除非您應用其他選項之一。

  2. 您可以使用類型不能為 null 的顯式 Id 屬性:

     public class Message { //... public Guid AuthorId { get; set; } public Role Author { get; set; } //... }

    注意 (i) - 這僅在您遵循 EF Core 影子屬性命名規則時才有效,在這種情況下,這意味着您必須將 Id 屬性命名為nameof(Author) + nameof(Role.Id) == AuthorId
    注意 (ii) - 如果有一天您決定重命名AuthorRole.Id但忘記相應地重命名AuthorId ,這將中斷。

  3. 如果您不能或不想更改 Model class,那么您可以告訴 EF Core 它需要按要求處理 shadow 屬性:

     builder.Property("AuthorId").IsRequired();

    2中列出的相同的注釋適用,此外您現在可以使用nameof()來減少工作量和風險。


最后我決定使用[Required]方法,因為

  • 它簡單明了,
  • 無需考慮使用哪個影子屬性名稱,
  • 以后沒有破壞影子屬性名稱的風險。

這有時可能適用,但並非總是如此:

  • 輸入 forms 可以使用 Model class 屬性來檢查是否需要屬性。 然而,圍繞DTO 類構建 forms 可能是一種更好的方法,然后在EF Model class上的屬性可能對您的 ZAC68B68AB61DZ 沒有任何價值。

暫無
暫無

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

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