Creating BiDirectional One - One relationship in Entity Framework 4.1 Code First
Asked Answered
W

1

11

I want to created Bi-Directional One-One relationship between two entities using EF Code First. I have trouble with the following code. What do you think I should do?

public class User
{
    public string ID { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }

    public int ProfileID { get; set; }
    public Profile Profile { get; set; }

}
public class Profile
{
    public int UserID { get; set; }
    public User User { get; set; }
    public int ProfileID { get; set; }
    public string ProfileName { get; set; }

    public DateTime CreateDate { get; set; }
    public DateTime LastUpdateDate { get; set; }

}

I want to have both Navigation property and Foreign Key in both the entities.

This gives me error. What can do I in Fluent Mapping API to make this work?

Whithersoever answered 8/6, 2011 at 8:47 Comment(0)
C
18

Use this:

public class User
{
    public string ID { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public Profile Profile { get; set; }
}

public class Profile
{
    [Key, ForeignKey("User")]
    public int ProfileID { get; set; }
    public string ProfileName { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime LastUpdateDate { get; set; }
    public User User { get; set; }
}

That is the only valid way to build one-to-one relation in EF - PK of the dependent entity must be also FK to principal entity. There is nothing like bidirectional one-to-one relation in EF because it cannot work in EF.

The way how people sometimes overcome this are two one-to-many relations where principal doesn't have navigation collection for dependent entities + manually defined unique keys in the database. That require manual mapping:

public class User
{
    public string ID { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    // one side MUST be nullable otherwise you have bidirectional constraint where each
    // entity demands other side to be inserted first = not possible
    public int? ProfileId { get; set; } 
    public Profile Profile { get; set; }
}

public class Profile
{
    public int ProfileID { get; set; }
    public string ProfileName { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime LastUpdateDate { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
}

And in mapping you will define:

modelBuilder.Entity<User>
            .HasOptional(u => u.Profile)
            .WithMany()
            .HasForeignKey(u => u.ProfileId);
modelBuilder.Entity<Profile>
            .HasRequired(u => u.User)
            .WithMany()
            .HasForeignKey(u => u.UserId);

Now you must define Unique keys in the database - if you are using code first use custom database initializer. Be aware that still bidirectional one-to-one is wrong concept because both sides demand unique FK where NULL is still included in unique values so once you insert User before Profile there mustn't be any other User without Profile. That probably leads to serializable transaction.

Coolie answered 8/6, 2011 at 8:56 Comment(4)
Ladislav, Now it makes perfect sense... I understand how the relationships are made... although I agree it should've been supported in a better way that creating unique key manually...Whithersoever
why WithMany if this is one-to-one relation?Obsess
@angel: It is a workaround to overcome limitations of EF - second part of the answer is cheating EF by telling it that there are two one-to-many relations instead of mapping one-to-one directly. One-to-one is ensured on database level by putting unique key constraints on foreign key columns.Coolie
@LadislavMrnka what about an update of the foreign key in User table? Is it possible? I mean changing the profile of a user (although it doesn't make sense in this example and makes sense in another examples)Cantu

© 2022 - 2024 — McMap. All rights reserved.