简体   繁体   中英

One-to-one relationship in CF Entity Framework using mapping

I'm using Entity Framework 5, Code-First.

I've two domain objects (or tables). 1st is User , and 2nd is UserProfile . One user can have only one profile, and one profile belongs to only one user. That is 1-1 relationship.

Here are the classes.... (I simplified the code to make it understandably, It is actually more complex)

User

public class User {
    public virtual Int64 UserId { get; set; }
    public virtual UserProfile UserProfile { get; set; }
    public virtual String Username{ get; set; }
    public virtual String Email { get; set; }
    public virtual String Password { get; set; }
}

UserProfile

public class UserProfile {
    public virtual Int64 UserId { get; set; }
    public virtual User User { get; set; }
    public virtual Int64 Reputation { get; set; }
    public virtual String WebsiteUrl { get; set; }
}

Here are the Maps....

UserMap

public UserMap() {
    this.Property(t => t.Email)
        .IsRequired()
        .HasMaxLength(100);
    this.Property(t => t.Password)
        .IsRequired()
        .HasMaxLength(15);
    this.Property(t => t.Username)
        .IsRequired()
        .HasMaxLength(15);
}

UserProfileMap

public UserProfileMap()
    {
        this.HasKey(t => t.UserId);
    }

Here is the Context....

public class TcContext : DbContext {
    static TcContext () {
        Database.SetInitializer(new TcContextInitializer());
    }
    public DbSet<User> Users { get; set; }
    public DbSet<UserProfile> UserProfiles { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Configurations.Add(new UserMap());
        modelBuilder.Configurations.Add(new UserProfileMap());
    }
}

And here is my error message....

Unable to determine the principal end of an association between the types 'Tc.Domain.UserProfile' and 'Tc.Domain.User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

I think in this way EF should determine the relationship automatically. But it gives me the above error message. I've researched this problem for a while but can't find a good illustration of the problem in my case.

Where is my mistake? Or, should I define some sort of additional relations in maps?

I had to modify the UserMap class as follows

public UserMap() {
    this.Property(t => t.Email)
        .IsRequired()
        .HasMaxLength(100);
    this.Property(t => t.Password)
        .IsRequired()
        .HasMaxLength(15);
    this.Property(t => t.Username)
        .IsRequired()
        .HasMaxLength(15);
    this.HasOptional(t => t.UserProfile)
        .WithRequired(t => t.User);
}

It essentially says: "User has an optional entity UserProfile which in turn has a required User entity"

The definition of the key in UserProfile is a must here.

Just looked at it again, do you need to add HasKey to UserMap so it knows which one is the key otherwise you could do the following :-

Are you able to change UserProfile to inherit from User and then add this to your OnModelCreating method

modelBuilder.Entity().ToTable("UserProfile");

this will create your one to one relationship on the database. I had to do this with my current model to get one to one otherwise if you do not specify the ToTable part it will lump them into one table with a Discriminator column

cheers Mark

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