15

How should I define relationships using Code First but without using any navigation properties?

Previously I have defined One-Many and Many-Many by using navigation properties in both ends of the relationship. And the appropriate relationships are created in the database. here's a stripped down version of how the classes look like (I've converted the Many-Many relationships to one-many for simplicity).

public class User 
{
    public string UserId { get; set; }
    public string PasswordHash { get; set; }
    public bool IsDisabled { get; set; }
    public DateTime AccessExpiryDate { get; set; }
    public bool MustChangePassword { get; set; }

    public virtual Role Role { get; set; }
}

public class Role
{
    public int RoleId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public virtual ICollection<User> Users { get; set; }
    public virtual ICollection<Right> Rights { get; set; }
}

public class Right
{
    public Guid RightId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public virtual Role Role { get; set; }
}

However, if I remove the navigation properties, no relationships are being created. Here's how the classes would look like.

public class User 
{
    public string UserId { get; set; }
    public string PasswordHash { get; set; }
    public bool IsDisabled { get; set; }
    public DateTime AccessExpiryDate { get; set; }
    public bool MustChangePassword { get; set; }

    public int Role RoleId { get; set; }
}

public class Role
{
    public int RoleId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class Right
{
    public Guid RightId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public int RoleId { get; set; }
}

notice that instead of a navigation property, I have the primary key of the related table. Everything gets created on the table - except the relationship. So how do I get about doing this?

BTW, I've tried various combinations in the OnModelCreating method of the dbcontext but to no avail. Any help is much appreciated!

Thanks, Mel

Mel
  • 3,058
  • 4
  • 26
  • 40

3 Answers3

24

I believe you always need navigation property on at least one side when using code-first. Then you will be able to map it:

public class User  
{     
    public string UserId { get; set; }     
    public string PasswordHash { get; set; }     
    public bool IsDisabled { get; set; }     
    public DateTime AccessExpiryDate { get; set; }     
    public bool MustChangePassword { get; set; }      
    public int RoleId { get; set; }
    public Role Role { get; set; }
}  

public class Role 
{     
    public int RoleId { get; set; }     
    public string Name { get; set; }     
    public string Description { get; set; } 
}  

public class Right 
{     
    public Guid RightId { get; set; }     
    public string Name { get; set; }     
    public string Description { get; set; }      
    public int RoleId { get; set; }
    public Role Role { get; set; }
} 

public class TestContext : DbContext
{
    public TestContext() : base("Entities")
    {}

    protected override void  OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<User>()
            .HasRequired(r => r.Role)
            .WithMany()
            .HasForeignKey(r => r.RoleId);

        modelBuilder.Entity<Right>()
            .HasRequired(r => r.Role)
            .WithMany()
            .HasForeignKey(r => r.RoleId);
    }
}
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I have suspected as much. Thanks for the example. I have tried using navigation properties along with the foreign key but the foreign key is not populated, but it looks like the answer is in your example. Thanks! – Mel Mar 09 '11 at 02:57
  • Would you need to define the ID properties if a property exists for the actual object? So in the User object would you need to define the RoleId or is that just for convenience? – DDiVita Apr 11 '11 at 20:01
  • 1
    @DDiVita: It is a big difference if you define `RoleId` in `User` or not. I recommend this answer to see a difference: http://stackoverflow.com/questions/5281974/code-first-independent-associations-vs-foreign-key-associations/5282275#5282275 – Ladislav Mrnka Apr 11 '11 at 20:07
1

You can use the fluent api to add the relationship, though the "configuration" code is separate from the entity code making it less discoverable.

robrich
  • 13,017
  • 7
  • 36
  • 63
-1

In EF 4.3, you can add a Migration that adds the relationship.

robrich
  • 13,017
  • 7
  • 36
  • 63