当两个 类 之间有多个不同的(一对多、多对多)关系时如何注释模型 类
How to annotate model classes when you have multiple different (one-to-many, many-to-many) relationships between two classes
我正在尝试将代码优先和数据注释与 EF 6.0 一起使用,具有以下非常简单的两个模型 类:基本上是可以成为活动组织者和参与者的员工:
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
public virtual ICollection<Event> event { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
public virtual ICollection<Employee> atendees { get; set; }
}
当我让 EF 从这些 类 生成数据库时,它令人惊讶地没有生成 Employee 和 Event 之间的多对多关系(因此,没有 EmployeeEvent 多对多 table),而是在 Employees 中生成一个事件 ID 外键。 (我不知道为什么。)
当然,我可以使用 fluent-APIs 直接创建正确的数据库映射,但我想知道是否有一种方法可以通过数据注释实现这一点。
您所描述的模型对您来说可能看起来很简单,但从数据库设计的角度来看并不是那么微不足道,这就是 EF 无法正确派生 "obvious" 配置的原因。
首先,Employee
和 Event
之间实际上有 2 个关系:
(1) 一对多员工 -> 描述员工正在组织的事件的事件
(2) 多对多员工 -> 描述员工正在参加的事件的事件
所以模型应该是这样的:
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
public virtual ICollection<Event> organizingEvents { get; set; }
public virtual ICollection<Event> attendingEvents { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
public virtual ICollection<Employee> attendees { get; set; }
}
另一个问题是这种模型可能会产生循环级联删除问题。说到限制,级联选项不能用数据注释指定,所以它确实需要一个流畅的配置。一旦它无论如何都需要它,为什么还要费心数据注释,让我们用 fluent API:
完全配置关系
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasMany(e => e.organizingEvents)
.WithRequired(e => e.organizer)
.HasForeignKey(e => e.organizerId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Employee>()
.HasMany(e => e.attendingEvents)
.WithMany(e => e.attendees);
}
作为@Ivan Stoev 的回答,你可以使用流利的 API 作为 well.If 你真的想通过数据注释来实现这一点,你可以有一个 class 用于中间 table 并且您可以使用一对多映射 relationships.Try 以下内容:
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
public virtual ICollection<middle_table> Middle_table{ get; set; }
public virtual ICollection<Event> event { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
public virtual ICollection<middle_table> Middle_table{ get; set; }
}
public class your_middle_class
{
public Guid Id { get; set; }
public virtual Employee organizer { get; set; }
public virtual Event Event{ get; set; }
}
我认为 Employee organizer
使 EF 混淆,这就是为什么 Ef 认为 你有一个一对多关系;如果是这种情况,那么您可以使用 InverseProperty 解决它,正如@Corak 所说
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[InverseProperty("atendees")]
public virtual ICollection<Event> event { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
[InverseProperty("event")]
public virtual ICollection<Employee> atendees { get; set; }
}
不用FluentAPI
就可以解决问题了
此外,有关 InverseProperty 的更多信息,您可以查看 this answer
我正在尝试将代码优先和数据注释与 EF 6.0 一起使用,具有以下非常简单的两个模型 类:基本上是可以成为活动组织者和参与者的员工:
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
public virtual ICollection<Event> event { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
public virtual ICollection<Employee> atendees { get; set; }
}
当我让 EF 从这些 类 生成数据库时,它令人惊讶地没有生成 Employee 和 Event 之间的多对多关系(因此,没有 EmployeeEvent 多对多 table),而是在 Employees 中生成一个事件 ID 外键。 (我不知道为什么。)
当然,我可以使用 fluent-APIs 直接创建正确的数据库映射,但我想知道是否有一种方法可以通过数据注释实现这一点。
您所描述的模型对您来说可能看起来很简单,但从数据库设计的角度来看并不是那么微不足道,这就是 EF 无法正确派生 "obvious" 配置的原因。
首先,Employee
和 Event
之间实际上有 2 个关系:
(1) 一对多员工 -> 描述员工正在组织的事件的事件
(2) 多对多员工 -> 描述员工正在参加的事件的事件
所以模型应该是这样的:
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
public virtual ICollection<Event> organizingEvents { get; set; }
public virtual ICollection<Event> attendingEvents { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
public virtual ICollection<Employee> attendees { get; set; }
}
另一个问题是这种模型可能会产生循环级联删除问题。说到限制,级联选项不能用数据注释指定,所以它确实需要一个流畅的配置。一旦它无论如何都需要它,为什么还要费心数据注释,让我们用 fluent API:
完全配置关系protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasMany(e => e.organizingEvents)
.WithRequired(e => e.organizer)
.HasForeignKey(e => e.organizerId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Employee>()
.HasMany(e => e.attendingEvents)
.WithMany(e => e.attendees);
}
作为@Ivan Stoev 的回答,你可以使用流利的 API 作为 well.If 你真的想通过数据注释来实现这一点,你可以有一个 class 用于中间 table 并且您可以使用一对多映射 relationships.Try 以下内容:
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
public virtual ICollection<middle_table> Middle_table{ get; set; }
public virtual ICollection<Event> event { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
public virtual ICollection<middle_table> Middle_table{ get; set; }
}
public class your_middle_class
{
public Guid Id { get; set; }
public virtual Employee organizer { get; set; }
public virtual Event Event{ get; set; }
}
我认为 Employee organizer
使 EF 混淆,这就是为什么 Ef 认为 你有一个一对多关系;如果是这种情况,那么您可以使用 InverseProperty 解决它,正如@Corak 所说
public class Employee
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[InverseProperty("atendees")]
public virtual ICollection<Event> event { get; set; }
}
public class Event
{
[Key]
public Guid Id { get; set; }
public string name { get; set; }
[ForeignKey("organizer")]
public Guid organizerId { get; set; }
public virtual Employee organizer { get; set; }
[InverseProperty("event")]
public virtual ICollection<Employee> atendees { get; set; }
}
不用FluentAPI
就可以解决问题了此外,有关 InverseProperty 的更多信息,您可以查看 this answer