使用Fluent API的EF 6 Code First关系。如何设置第一个和第三个表之间的关系或获取分组集合

时间:2017-07-12 08:50:44

标签: entity-framework ef-code-first relationship ef-fluent-api

我有三个相关的实体,这里是使用Fluent API声明的结构和关系

参加许多人(实际上是一群人)的活动,因此有可能通过GroupID收集所有人。那怎么做呢?

public class Event
{
    public int EventID { get; set; }
    public string DocID { get; set; }
    public string GroupID { get; set; }
    public virtual Person Person { get; set; }
    public virtual Group Group { get; set; }
    public virtual ICollection<Person> GroupPerson {get; set}
}

人实体,这里我有关于人的所有信息,如姓名,姓氏,生日...

public class Person
{
    public string PersonID { get; set; }
    public string PersonName { get; set; }
    public string PersonSurName { get; set; }
    public string PersonCode { get; set; } 
}    

群组实体,这是有关群组的信息

public class Group
{
    public string GroupID { get; set; }
    public string GroupName { get; set; }
    public virtual ICollection<Event> EventGroup { get; set; }
}

现在我使用Fluent API描述关系。主键首先是:

modelBuilder.Entity<Event>().HasKey(e => e.EventID);  
modelBuilder.Entity<Person>().HasKey(e => e.PersonID);  
modelBuilder.Entity<Group>().HasKey(e => e.GroupID);

在这里,我将有与事件有关的人

modelBuilder.Entity<Event>()
                .HasRequired(s => s.Person)
                .WithMany()
                .HasForeignKey(fk=> fk.PersonID); 

这里我将有PersonGroup

 modelBuilder.Entity<Group>()
               .HasKey(e => e.GroupID)
               .HasMany(e => e.EventGroup)
               .WithOptional()
               .HasForeignKey(f => f.GroupID);

我的问题是如何建立关系以获得群组中的人员列表? PersonGroup类型为Event,我需要Person => ICollection<Person> GroupPerson类中的人员列表:Event

1 个答案:

答案 0 :(得分:1)

鉴于你的关系是这样的:

  • 一个事件与(仅与之相关)一组(必需)
  • 一个小组(从零到多个事件相关)
  • 一个群体(与之相关)零到多人
  • 一个人(与...有关)零到多个群组

也就是说,您的关系事件 - 群组是一对多的,您的关系群组 - 人物是多对多的(我假设同一个人可以在多个群组中)。事件和人之间没有直接的关系,但是传递关系事件 - &gt;组 - &gt;人

然后可以这样建模:

public class Event
{
    public int EventID { get; set; }
    public string DocID { get; set; }
    public string GroupID { get; set; }
    public virtual Group Group { get; set; }
    public virtual ICollection<Person> People { get { return Group.People; } }
}

public class Person
{
    public string PersonID { get; set; }
    public string PersonName { get; set; }
    public string PersonSurName { get; set; }
    public string PersonCode { get; set; }
}

public class Group
{
    public string GroupID { get; set; }
    public string GroupName { get; set; }
    public virtual ICollection<Event> Events { get; set; }
    public virtual ICollection<Person> People { get; set; }
}

DbContext中使用这些DbSet:

public DbSet<Person> People { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Event> Events { get; set; }

这个EF配置:

modelBuilder.Entity<Event>()
    .HasKey(e => e.EventID)
    .Ignore(e => e.People)
    .HasRequired(e => e.Group)
    .WithMany(g => g.Events);

modelBuilder.Entity<Group>()
    .HasKey(g => g.GroupID)
    .HasMany(g => g.People)
    .WithMany();

 modelBuilder.Entity<Person>()
    .HasKey(p => p.PersonID);

请注意,Ignore()有明确的Event.People。这是因为Event和Person之间的关系是可传递的,您不需要为数据库添加额外的列。如果您不明白为什么,请尝试注释掉Ignore()行并重新生成迁移,并看到在“人员”表格中生成了一个额外的事件ID列(此列不会生成很有道理)。

因此,People中的Events属性未由EF填充,您必须自己完成:

public virtual ICollection<Person> People { get { return Group.People; } }

要将人员添加到活动中,您应该使用组导航属性,如下所示:

public class Event
{
    ...

    public void AddPerson(Person p)
    {
        this.Group.People.Add(p);
    }
}

使用此代码,迁移就像这样生成,包含四个表:EventsGroupsPeople和额外的表PeopleGroups,用于多对多人与群的关系。

    public override void Up()
    {
        CreateTable(
            "dbo.Events",
            c => new
                {
                    EventID = c.Int(nullable: false, identity: true),
                    DocID = c.String(),
                    GroupID = c.String(nullable: false, maxLength: 128),
                })
            .PrimaryKey(t => t.EventID)
            .ForeignKey("dbo.Groups", t => t.GroupID, cascadeDelete: true)
            .Index(t => t.GroupID);

        CreateTable(
            "dbo.Groups",
            c => new
                {
                    GroupID = c.String(nullable: false, maxLength: 128),
                    GroupName = c.String(),
                })
            .PrimaryKey(t => t.GroupID);

        CreateTable(
            "dbo.People",
            c => new
                {
                    PersonID = c.String(nullable: false, maxLength: 128),
                    PersonName = c.String(),
                    PersonSurName = c.String(),
                    PersonCode = c.String(),
                })
            .PrimaryKey(t => t.PersonID);

        CreateTable(
            "dbo.GroupPersons",
            c => new
                {
                    Group_GroupID = c.String(nullable: false, maxLength: 128),
                    Person_PersonID = c.String(nullable: false, maxLength: 128),
                })
            .PrimaryKey(t => new { t.Group_GroupID, t.Person_PersonID })
            .ForeignKey("dbo.Groups", t => t.Group_GroupID, cascadeDelete: true)
            .ForeignKey("dbo.People", t => t.Person_PersonID, cascadeDelete: true)
            .Index(t => t.Group_GroupID)
            .Index(t => t.Person_PersonID);

    }

如果您不喜欢关系表GroupPersons中列的名称,则可以添加.Map()配置(但您不需要这样做,因为这个表格没有直接使用,没有模型实体,它在DbSet中甚至没有DbContext属性。