为了账号安全,请及时绑定邮箱和手机立即绑定

EF Code-First一对一关系:角色*中的多重性无效

/ 猿问

EF Code-First一对一关系:角色*中的多重性无效

狐的传说 2019-11-30 14:52:36

我正在尝试执行以下操作:


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”中无效。因为从属角色属性不是关键属性,所以从属角色多重性的上限必须为'*'。


这里可能是什么问题?


查看完整描述

3 回答

?
慕用2447696

您的模型不是1:1关联。您仍然可以有许多 Class2对象引用同一个 Class1对象。同样,您的模型也不保证该对象也返回了Class2对a Class1的引用Class1- Class1可以引用任何Class2对象。


如何配置1:1?

在SQL中保证1:1关联的一种常见方法是为主体实体创建一个表,为从属实体提供一个表,其中从属表中的主键也是主体的外键:


1:1


(这Class1是校长)


现在在关系数据库中,这仍然不能保证1:1关联(这就是我说“排序”的原因)。这是1:0..1关联。可以有一个Class1没有的Class2。事实是,在SQL中不可能实现真正的1:1关联,因为没有语言构造可以在不同表中同步插入两行。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不会阻止您创建(和保存)没有的class1对象。我认为EF应该能够在保存更改之前验证此要求,但是显然不能。同样,有一些方法可以删除对象而不删除其父对象。因此,这对- 看上去并不严格(应该如此)。class2class2class1HasRequiredWithRequired


数据注解


在代码中获得此权限的唯一方法是通过数据注释。(当然,数据库模型仍将无法强制执行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不仅使用它们来设计数据模型,还用于验证实体。现在,如果您尝试不使用保存class1对象,class2则会收到验证错误。


查看完整回答
反对 回复 2019-11-30
?
慕容森

我有同样的问题。我想要的是DB模式具有2个表,这些表使用[外键]-> [主键]相互交叉引用。最终,我找到了方法:假设我们有2个课:书籍和作者。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


...



查看完整回答
反对 回复 2019-11-30
?
拉莫斯之舞

必须先创建两个类中的一个,然后需要[Required]批注。如果Class2依赖于Class1,则指定[Required,ForeignKey(“ Class1”)]。您也可以使用fluent API在上下文类中进行配置。


查看完整回答
反对 回复 2019-11-30

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信