Unable to determine the principle end of an associ

2019-03-01 15:38发布

问题:

Using EF5 Code first, I have two classes:

[Table("UserProfile")]
public class UserProfile {

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime DateOfBirth { get; set; }

    [ForeignKey("AddressId")]
    public virtual Address Address { get; set; }

}

[Table("Address")]
public class Address : IEntity {

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int AddressId { get; set; }

    public string Address1 { get; set; }

    public string Address2 { get; set; }

    public string City { get; set; }

    public virtual State State { get; set; }

    public string ZipCode { get; set; }

    [ForeignKey("UserId")]
    public virtual UserProfile User { get; set; }
}

UserProfile should always have an Address but I also wanted to have a navigation property in Address so that I could look up users by address. So, once migrations has done its thing, I'd like the tables to look like...

UserProfile
    UserId (PK)
    ...

Address
    AddressId (PK)
    ...
    UserId (FK)

From the Package Manager Console, I'm running update-database and getting the following message...

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

I'm confused on how to set up one-to-one relationships in Entity Framework 5.

回答1:

You define the principal when you map:

modelBuilder.Entity<Bar>()
            .HasOptional(f => f.Baz). //Baz is dependent and gets a FK BarId
            .WithRequired(s => s.Bar);//Bar is principal

modelBuilder.Entity<Baz>()
            .HasOptional(f => f.Bar). //Bar is dependent and gets a FK BazId
            .WithRequired(s => s.Baz);//Baz is principal

The dependent gets the foreign key that references the principal's key. When it's a one to one, that foreign key is also the dependent's primary key but EF can't work out which is which and that's why you get an error until you've specified it.

References:

http://msdn.microsoft.com/en-us/library/ee382827.aspx

https://stackoverflow.com/a/19580798/150342



回答2:

The trick with 1:1 in EF is the dependant table MUST have the same primary key. The Primary tables has the DB generated ID. The dependant uses DatabaseGeneratedOption.None !

so the fluentAPI for the dependant table

 {
  // map for Dependant
  // Relationship
        this.HasKey(t => t.Id);
        // Properties
        //Id is an int allocated by DB but controller via Primary here
        this.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); // from parent
        entity.HasRequired(t => t.NAV_PROP_TO_PRIMARY)
              .WithOptional(t => t.NAV_PROP_DEPENDANT) // if it is declared. NOT required.
              .WillCascadeOnDelete(true);   // as appropriate
 }   

 {
     //map for Primary
     // Primary Key
     this.HasKey(t => t.Id);

     // Properties
     //Id is an int allocated by DB
    this.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // default to db generated

 }


public class Dependant{ 
   public  virtual int Id { set; get; }
   //... other props
   public virtual Primary Primary {get; set;}   // nav to primary
} 

public class Primary{ 
   public  virtual int Id { set; get; }

}