James
James

Reputation: 696

Entity Framework, code-first: combining master-detail with zero-to-one relationship

I have a simple master-detail relationship using code first EF:

public class User
{
     public string Id { get; set; }
     public ICollection<Tasks> Tasks { get; set; }
}

public class Task
{
    public string Id { get; set; }

    [Required]
    public string UserId { get; set; }
    public User User { get; set; }
}

Now I want to modify it so that users can have a single, most important task. So I modify the User class to add it:

public class User
{
     public string Id { get; set; }
     public ICollection<Tasks> Tasks { get; set; }
     public string MostImportantTaskId { get; set; }

     [ForeignKey("MostImportantTaskId")]
     public Task MostImportantTask { get; set; }
}

When I run Add-Migration, however, I get an unexpected result. EF is trying to add a User_Id column to the Tasks table, which I don't want, and dropping the foreign key I need for the master/detail relationship:

public override void Up()
{
    DropForeignKey("dbo.Tasks", "UserId", "dbo.Users");
    AddColumn("dbo.Tasks", "User_Id", c => c.String(maxLength: 128));
    AddColumn("dbo.Users", "MostImportantTaskId", c => c.String(maxLength: 128));
    CreateIndex("dbo.Tasks", "User_Id");
    CreateIndex("dbo.Users", "MostImportantTaskId");
    AddForeignKey("dbo.Users", "MostImportantTaskId", "dbo.Tasks", "Id");
    AddForeignKey("dbo.Tasks", "User_Id", "dbo.Users", "Id");
}

public override void Down()
{
    // ...
}

So how do I maintain the master detail relationship between users and tasks, while adding a reference to a single task to the User class?

Upvotes: 3

Views: 1920

Answers (1)

Tone
Tone

Reputation: 1735

It's not something I'm overly familiar with but I believe what you're looking for is InverseProperty. As your User class has multiple relationships with Task, you need to add the InverseProperty to your Tasks collection to point it to the User property on Task.

So if you make this change in your User class

[InverseProperty("User")]
public ICollection<Task> Tasks { get; set; }

then when you run a migration the following code gets generated, which looks to be what you're after

public override void Up()
{
    AddColumn("dbo.Users", "MostImportantTaskId", c => c.String(maxLength: 128));
    CreateIndex("dbo.Users", "MostImportantTaskId");
    AddForeignKey("dbo.Users", "MostImportantTaskId", "dbo.Tasks", "Id");
}

public override void Down()
{
    DropForeignKey("dbo.Users", "MostImportantTaskId", "dbo.Tasks");
    DropIndex("dbo.Users", new[] { "MostImportantTaskId" });
    DropColumn("dbo.Users", "MostImportantTaskId");
}

Based on an example at entityframeworktutorial.net.

Note: I've assumed where you've referenced a Tasks class in your code it was a typo for Task.

Upvotes: 3

Related Questions