Search code examples
c#sql.netentity-frameworkfluent

EF6 how to map this zero or one to one relationship


This is Code-First.

What's the correct Fluent or data annotation for this relationship?

Getting EF mapping error: Unable to determine the principal end of an association between the types 'Model.SchoolInfo' and 'Model.School'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

If I add

modelBuilder.Entity<School>().HasOptional(s => s.SchoolInfo).WithRequired(ss => ss.School);

I get this error: One or more validation errors were detected during model generation: School_SchoolInfo_Target: : Multiplicity is not valid in Role 'School_SchoolInfo_Target' in relationship 'School_SchoolInfo'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.

SQL Tables

table School
(
    int SchoolId not null PK
)

table SchoolInfo
(
    int SchoolInfoId not null PK IDENTITY
    int SchoolId not null FK UNIQUE
)

Models

class School
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    int schoolId;

    virtual SchoolInfo SchoolInfo;
}

class SchoolInfo
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    int schoolInfoId;

    int schoolId;

    virtual School School
}

Solution

  • If you want to implement 1:1 mapping, this is how tables should look like:

    Schools

    SchoolInfoes

    And your entity classes in that case would look like this:

    public class School
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int SchoolId { get; set; }
    
        public virtual SchoolInfo SchoolInfo { get; set; }
    }
    
    public class SchoolInfo
    {
        [ForeignKey("School")]
        public int SchoolInfoId { get; set; }
    
        public virtual School School { get; set; }
    }
    

    Your current table structure suggests 1:M mapping, and in order to map entity classes to it, you need to do slight changes:

    public class School
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int SchoolId;
    
        public virtual IList<SchoolInfo> SchoolInfoes { get; set; }
    }
    
    public class SchoolInfo
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int SchoolInfoId { get; set; }
    
        public int SchoolId { get; set; }
    
        public virtual School School { get; set; }
    }