簡體   English   中英

EF Code-First 一對一關系:多重性在關系中的角色 * 中無效

[英]EF Code-First One-to-one relationship: Multiplicity is not valid in Role * in relationship

我正在嘗試執行以下操作:

public class class1
{
    public int Id {get;set;}
    [ForeignKey("Class2")]
    public int Class2Id {get;set;}
    public virtual Class2 Class2 {get;set;}
}

public class class2
{
    public int Id { get; set;}
    [Required]
    public virtual int Class1Id {get;set;}
    [Required]
    [ForeignKey("Class1Id")]
    public Class1 Class1 {get;set;}
}

但是,每次嘗試遷移數據庫時,都會出現以下錯誤:

Class1_Class2_Target::多重性在關系“Class2_Class1”中的角色“Class2_Class1_Target”中無效。 由於從屬角色屬性不是關鍵屬性,因此從屬角色的重數上限必須為“*”。

這里可能是什么問題?

您的模型不是 1:1 的關聯。 您仍然可以有多個Class2對象引用同一個Class1對象。 此外,您的模型不保證引用Class1Class2也會被此Class1對象引用回來Class1可以引用任何Class2對象。

如何配置1:1?

在 SQL 中保證(某種程度)1:1 關聯的常用方法是為主體實體創建一個表,為依賴實體創建一個表,其中依賴表中的主鍵也是主體的外鍵:

1:1

(這里Class1是校長)

現在在關系數據庫中,這仍然不能保證 1:1 關聯(這就是我說“有點”的原因)。 這是一個1:0..1 的關聯。 可以有沒有Class2Class1 事實是,真正的 1:1 關聯在 SQL 中是不可能的,因為沒有將兩行同步插入不同表中的語言結構。 1:0..1 是我們得到的最接近的。

流暢的映射

要在 EF 中對這種關聯進行建模,您可以使用 fluent API。 這是執行此操作的標准方法:

class Class1Map : EntityTypeConfiguration<Class1>
{
    public Class1Map()
    {
        this.HasKey(c => c.Id);
        this.Property(c => c.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        this.HasRequired(c1 => c1.Class2).WithRequiredPrincipal(c2 => c2.Class1);
    }
}

在上下文中:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new Class1Map());
}

這是您的課程的剩余部分:

public class Class1
{
    public int Id {get;set;}
    public virtual Class2 Class2 {get;set;}
}

public class Class2
{
    public int Id {get;set;}
    public virtual Class1 Class1 {get;set;}
}

無法在模型中配置備用外鍵屬性,因為唯一涉及的 FK必須是依賴項的主鍵。

這個模型的奇怪之處在於 EF 不會阻止您創建(和保存)沒有class2class1對象。 我認為 EF 應該能夠在保存更改之前驗證此要求,但顯然它沒有。 同樣,有一些方法可以刪除class2對象而不刪除其class1父對象。 所以這個HasRequired - WithRequired對並不像它看起來(應該是)那么嚴格。

數據注釋

在代碼中實現這一點的唯一方法是通過數據注釋。 (當然數據庫模型仍然無法強制執行 1:1)

public class Class1
{
    public int Id {get;set;}
    [Required]
    public virtual Class2 Class2 {get;set;}
}

public class Class2
{
    [Key, ForeignKey("Class1")]
    public int Id {get;set;}
    [Required]
    public virtual Class1 Class1 {get;set;}
}

[Key, ForeignKey("Class1")]注釋告訴 EF Class1是主體實體。

數據注解在很多 API 中都有作用,這可能是個詛咒,因為每個 API 都選擇自己的子集來實現,但在這里它派上用場了,因為現在 EF 不僅使用它們來設計數據模型,還用於驗證實體. 現在,如果您嘗試在沒有class2情況下保存class1對象,則會收到驗證錯誤。

我有同樣的問題。 我想要的是數據庫模式有 2 個表,這些表通過 [外鍵] --> [主鍵] 相互引用。 最后我找到了方法:假設我們有 2 個類:Books 和 Authors。 Book 類應該有一個指向作者的外鍵,而 Author 類應該有一個他寫的最后一本書的外鍵。 首先使用代碼讓 EF 理解這一點的方法是:(請注意,這是使用數據注釋和 fluent API 的混合完成的)

public class Book {
    ...
    public Guid BookId
    ...
    public Guid AuthorId { get; set; }

    [ForeignKey("AuthorId")]
    public virtual Author author { get; set; }
}

public class Author {
    ...
    public Guid AuthorId
    ...
    public Guid? LatestBookId { get; set; }

    [ForeignKey("LatestBookId")]
    public virtual Book book { get; set; }

    public virtual ICollection<Book> books { get; set; }
}

// using fluent API
class BookConfiguration : EntityTypeConfiguration<Book> {

    public BookConfiguration() {
        this.HasRequired(b => b.author)
            .WithMany(a => a.books);
    }

}

這有效並創建了我想要的確切數據庫模式。 在 SQL 中,它將創建對應於以下代碼的表和外鍵:

CREATE TABLE [dbo].[Book](
    [BookId] [uniqueidentifier] NOT NULL,
    [AuthorId] [uniqueidentifier] NOT NULL,
    ...
 CONSTRAINT [PK_dbo.Book] PRIMARY KEY CLUSTERED 
(
    [BookId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

...

GO

ALTER TABLE [dbo].[Book] WITH CHECK ADD  CONSTRAINT [FK_dbo.Book.Author_AuthorId] FOREIGN KEY([AuthorId])
REFERENCES [dbo].[Author] ([AuthorId])
GO

...

CREATE TABLE [dbo].[Author](
    [AuthorId] [uniqueidentifier] NOT NULL,
    [LatestBookId] [uniqueidentifier] NULL,
    ...
 CONSTRAINT [PK_dbo.Author] PRIMARY KEY CLUSTERED 
(
    [AuthorId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

...

GO

ALTER TABLE [dbo].[Author]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Author_dbo.Book_LatestBookId] FOREIGN KEY([LatestBookId])
REFERENCES [dbo].[Book] ([BookId])
GO

...

這兩個類中的一個必須在另一個之前創建,因此需要 [Required] 注釋。 如果 Class2 依賴於 Class1,則指定 [Required, ForeignKey("Class1")]。 您也可以使用 fluent API 在您的上下文類中配置它。

暫無
暫無

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

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