简体   繁体   中英

How to create a table with two foreign keys pointing to the same table using Entity Framework Code First

I have the following classes, which I'm trying to store in a database using Entity Framework 6 code first.

Person:

public class Person
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public List<WorkItem> WorkItems { get; set; }
}

WorkItem:

public class WorkItem
{
    public Guid Id { get; set; }

    public string Description { get; set; }

    public Person Creator { get; set; }

}

As you can see each person can have a number of task. But(!) the task also has a creator that is a person.

I expect the workitem table created by using entity framework's add-migration to have two foreign keys. One so that the workitem can bleong to the WorkItems collection of Person, and one that points to the creator of the Workitem. Like the picture below shows:

在此处输入图片说明

This doesn't seem to be such a weird scenario, but it's causing me loads of problems.

If you just try to create database tables using add-migration the WorkItem is created in the following way:

            CreateTable(
            "dbo.WorkItems",
            c => new
                {
                    Id = c.Guid(nullable: false),
                    Description = c.String(),
                    Creator_Id = c.Guid(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.People", t => t.Creator_Id)
            .Index(t => t.Creator_Id);

As you can see there is nothing that makes the Person an owner of its work items here. If I remove the Creator property it works as expected. There seems to be a problem referencing a class when that class is the owner.

Why doesn't this just work out of the box and what is the best way to fix it? Navigation property? Fluent API?

Configure your entities using this configuration in your DbContext.OnModelCreating (or better yet, add separate entityconfigurations):

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
   modelBuilder.Entity<Person>().HasMany(p => p.WorkItems).WithMany();
   modelBuilder.Entity<WorkItem>().HasRequired(t => t.Creator).WithMany().WillCascadeOnDelete(false);
 }

This will create a table for Person and another for WorkItem and another one to support the many-to-many relationship between Person and WorkItem. It will also create a separate FK in WorkItem to reference Person:

在此处输入图片说明

I couldn't understand your question entirely. I understand that every person can have multiple tasks, but I'm not sure whether a task can be assigned to only one person or multiple people. If you want a one-to-many relationship only, use this configuration:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
   modelBuilder.Entity<Person>().HasMany(p => p.WorkItems).WithOptional();
   modelBuilder.Entity<WorkItem>().HasRequired(t => t.Creator).WithMany().WillCascadeOnDelete(false);
 }

This only creates the two tables and in WorkItem two FK-s to reference the Person table; one for the Creator and one so that EF can wire up the references in Person to the WorkItems:

在此处输入图片说明

This looks like as one to many relationship, so your Tasks property should be ICollection<WorkItem> , you need to update your both classes.

Your Person class would be like:

public class Person
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public ICollection<WorkItem> Tasks { get; set; }
}

and you would also need to modify your WorkItem class to have reference to the Person instance who created the WorkItem , so WorkItem class would be like:

public class WorkItem
{
    public Guid Id { get; set; }

    public string Description { get; set; }

    [ForeignKey("Person")]
    public Guid WorkItemCreatorId{ get; set; }

    public Person Creator { get; set; }

}

Now this should generate the correct sql in migrations.

For more on Entity Framework one-to-many relationships, please have a look here

Hope it works for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM