![](/img/trans.png)
[英]Multiplicity is not valid in Role in relationship: EF code first one to one relationship with same primary key and foreign key
[英]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
對象。 此外,您的模型不保證引用Class1
的Class2
也會被此Class1
對象引用回來Class1
可以引用任何Class2
對象。
在 SQL 中保證(某種程度)1:1 關聯的常用方法是為主體實體創建一個表,為依賴實體創建一個表,其中依賴表中的主鍵也是主體的外鍵:
(這里Class1
是校長)
現在在關系數據庫中,這仍然不能保證 1:1 關聯(這就是我說“有點”的原因)。 這是一個1:0..1 的關聯。 可以有沒有Class2
的Class1
。 事實是,真正的 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 不會阻止您創建(和保存)沒有class2
的class1
對象。 我認為 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.