Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating BiDirectional One - One relationship in Entity Framework 4.1 Code First

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?

like image 566
Preetham Reddy Avatar asked Jun 08 '11 08:06

Preetham Reddy


1 Answers

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.

like image 100
Ladislav Mrnka Avatar answered Oct 14 '22 10:10

Ladislav Mrnka