C# EF Code First一对一关系:多重性在关系中的角色*中无效
我正在尝试执行以下操作:C# EF Code First一对一关系:多重性在关系中的角色*中无效,c#,database,entity-framework,ef-code-first,entity-framework-6,C#,Database,Entity Framework,Ef Code First,Entity Framework 6,我正在尝试执行以下操作: 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] publi
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\u Class2\u目标::多重性在角色中无效
关系“Class2\u Class1”中的“Class2\u Class1\u目标”。因为
依赖角色属性不是键属性,而是上限
依赖角色的多重性必须为“*”
这里有什么问题?两个类中的一个必须先创建,因此需要[Required]注释。如果Class2依赖于Class1,则指定[Required,ForeignKey(“Class1”)]。您还可以在上下文类中使用fluent API来配置它。您的模型不是1:1关联。您仍然可以有许多
Class2
对象引用同一个Class1
对象。此外,您的模型不能保证引用Class1
的Class2
也被该Class1
对象引用回-Class1
可以引用任何Class2
对象
如何配置1:1?
在SQL中保证(某种程度上)1:1关联的常用方法是为主体实体和从属实体分别设置一个表,其中从属表中的主键也是主体的外键:
(这里Class1
是负责人)
现在在关系数据库中,这仍然不能保证1:1的关联(这就是为什么我说“有点”)。这是一种1:0..1关联。可以有Class1
而没有Class2
。事实是,真正的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);
}
}
这是你们剩下的课程:
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)
[Key,ForeignKey(“Class1”)]
注释告诉EFClass1
是主要实体
数据注释在许多API中扮演着一个角色,这可能是一个诅咒,因为每个API都选择自己的子集来实现,但在这里它很方便,因为现在EF不仅使用它们来设计数据模型,而且还用来验证实体。现在,如果您试图在没有
class2
的情况下保存class1
对象,您将得到一个验证错误。我遇到了完全相同的问题。
我想要的是DB模式有两个表,它们使用[foreign key]-->[primary key]相互交叉引用。
最后我找到了方法:
假设我们有两类:书籍和作者。
Book类应该有作者的外键,author类应该有他写的最后一本书的外键。
让EF首先使用代码理解这一点的方法是:
(请注意,这是通过混合使用数据注释和fluent API完成的)
我尝试在class2的外键中添加[Required]数据注释,但仍然得到相同的错误。(我还更新了我的代码以在我的问题中显示这一点)啊,外键值应该引用每个类中的int值,而不是类对象。因此,外键应该是“ClassID”,而不是“Class1”。Class2也是如此。我也尝试过(更新了我的问题代码),但仍然得到了相同的错误。奇怪的是:当我删除ClassID和Class2Id属性时,我再也没有得到错误了-给出了什么?fluent API方法令人惊讶,与annotations方法相比,它在配置方面很有意义+1.这不是一对一的关系
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;}
}
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;}
}
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);
}
}
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
...