EF代码 – 第一对一关系:多重性在关系中的angular色*中是无效的

我试图做到以下几点:

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 :: Multiplicity在关系“Class2_Class1”中的angular色“Class2_Class1_Target”中无效。 由于“依赖angular色”属性不是关键属性,所以“依赖angular色”的多重性的上界必须是“*”。

这里可能是什么问题?

您的模型不是1:1关联。 您仍然可以有多个引用同一个 Class1对象的Class2对象。 此外,您的模型不保证引用Class1Class2也被此Class1对象引用 – Class1可引用任何Class2对象。

如何configuration1:1?

在SQL中确保(sorting)1:1关联的常用方法是为主体实体提供一个表,并为依赖实体提供一个表,从属表中的主键也是主体的外键:

1:1

(这里Class1是主体)

现在在一个关系数据库中,这仍然不能保证1:1关联(这就是为什么我说'有点')。 这是一个1:0..1的关联。 可以有一个没有Class2Class1 。 事实上,真正的1:1关联在SQL中是不可能的,因为没有语言结构可以同时在不同的表中插入两行。 1:0..1是我们得到的最接近的。

stream利映射

要在EF中build立此关联,您可以使用stream畅的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;} } 

没有办法在模型中configuration备用外键属性,因为唯一涉及的FK 必须是从属的主键。

这个模型的奇怪之处在于,EF不会阻止您创build(并保存) 没有 class2class1对象。 我认为在保存更改之前,EF应该能够validation这个要求,但显然不是这样。 同样,也可以删除一个class2对象而不删除它的class1父对象。 所以这个HasRequiredWithRequired对并不像看起来(也应该是)那么严格。

数据注释

在代码中正确使用的唯一方法是通过数据注释。 (当然,数据库模型仍然不能执行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中扮演了一个angular色,这可能是一个诅咒,因为每个API都select它自己的子集来实现,但是在这里它派上用场,因为现在EF不仅使用它们来devise数据模型,而且还validation实体。 现在,如果您尝试保存没有class2class1对象,您将得到一个validation错误。

我有完全相同的问题。 我想要的是数据库模式有两个表,交叉引用彼此[外键] – > [主键]。 最后我find了方法:假设我们有两个类:书和作者。 Book类应该为作者创作一个外键,Author类应该在他写的最后一本书中有一个外键。 EF首先使用代码来理解这一点的方法是:(注意,这是通过混合使用数据注释和stream利的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); } } 

这工作,并创build我想要的确切的数据库架构。 在SQL中,它将创build对应于以下代码的表和外键:

 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 ... 

两个类中的一个必须在另一个之前创build,因此需要[Required]注释。 如果Class2依赖于Class1,则指定[Required,ForeignKey(“Class1”)]。 你也可以使用stream利的API来configuration你的上下文类。