EF Code-First一对一关系:Multiplicity在Role *关系中无效

时间:2014-10-15 18:36:00

标签: 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]
    public virtual int Class1Id {get;set;}
    [Required]
    [ForeignKey("Class1Id")]
    public Class1 Class1 {get;set;}
}

但是,每次尝试迁移数据库时,都会出现以下错误:

  

Class1_Class2_Target :: Multiplicity在Role中无效   关系'Class2_Class1'中的'Class2_Class1_Target'。因为   依赖角色属性不是关键属性,即上限   依赖角色的多样性必须是'*'。

这可能是什么问题?

3 个答案:

答案 0 :(得分:57)

您的模型不是1:1关联。您仍然可以使用许多 Class2个对象来引用相同的一个 Class1对象。此外,您的模型不保证此Class2对象也会引用引用Class1的{​​{1}} - Class1可以引用任何Class1对象

如何配置1:1?

在SQL中保证(排序)1:1关联的常用方法是为主体实体创建一个表,为依赖实体设置一个表,其中从属表中的主键也是主体的外键:

1:1

(这里Class2是校长)

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

Fluent Mapping

要在EF中建模此关联,您可以使用流畅的API。以下是执行此操作的标准方法:

Class2

在上下文中:

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());
}

无法在模型中配置备用外键属性,因为唯一涉及的必须依赖主键。

这个模型的奇怪之处在于EF不会阻止你创建(并保存)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;} } 对象而不用 class1。我认为EF应该能够在保存更改之前验证此要求,但显然,它没有。同样,有一些方法可以删除class2对象而不删除其class2父对象。因此,此class1 - HasRequired对并不像它看起来那样严格(应该是)。

数据注释

在代码中实现正确的唯一方法是通过数据注释。 (当然数据库模型仍然无法强制执行1:1)

WithRequired

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;} } 注释告诉EF [Key, ForeignKey("Class1")]是主要实体。

数据注释在许多API中扮演着一个角色,这可能是一个诅咒,因为每个API都选择自己的子集来实现,但这里派上用场,因为现在EF不仅使用它们来设计数据模型,还包括验证实体。现在,如果您尝试在没有Class1的情况下保存class1对象,则会收到验证错误。

答案 1 :(得分:3)

我遇到了完全相同的问题。 我想要的是DB模式有2个表,用[外键] - &gt;相互交叉引用[首要的关键]。 最后我找到了方法: 我们假设我们有两个类:书籍和作者。 Book类应该有一个创建它的作者的外键,而Author类应该有他写的最后一本书的外键。 让EF首先使用代码理解这一点的方法是: (请注意,这是使用数据注释和流畅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

...

答案 2 :(得分:0)

必须在另一个之前创建两个类中的一个,因此需要[Required]注释。如果Class2依赖于Class1,则指定[Required,ForeignKey(&#34; Class1&#34;)]。您也可以使用流畅的API在上下文类中配置它。