Entity Framework model class has conditional one-to-one relationship

asp.net-mvc c# entity-framework-6 foreign-key-relationship

Question

Here, I need some assistance. I'm having a lot of trouble building the models I need for my project based on my thoughts. I have a Parent table, a Student table, and an Address table to make things easier. Therefore, each Parent record might include more than one Student and just one address. There can be numerous Parents listed for each student, but there can only be one address. Since it is possible for students to have parents who reside in different places, I really can't presume that the student's address is the same as the parents' address. Therefore, I would like to be able to have both a student's address and a parent's address. Therefore, I basically see this database layout as an Address table with the columns AddressID, street, city, state, and zip. then a table for students with StudentID, name, and addressID. the Parent table, which contains the ParentID, name, and addressID. the StudentID and ParentID columns of a Parent Student reference database.

Any suggestions for how I can put this into practice? Only the address details and ID were used when I developed my Address Model. With an ID, name, virtual address, and virtual ICollection parent, I generated a student model. I then generated my Parent model, including the Virtual Address, Virtual ICollection, ID, and Name. I receive an error message regarding Visual Studio being unable to identify the principal end of an association between the types Parent and Address when I attempt to create my Student controller using New->Scaffolded Item.

This, I assume, is related to the fact that a foreign Key to either a Parent or a Student, but not both, will be present in an address record. Given that I'm very new to the code-first methodology, any advice would be highly welcomed. I appreciate it.


EDIT: Including REVISED Code

PEOPLE MODEL:

public enum PersonType
{
    Student, Parent, Teacher
}

public abstract class Person
{

    [Key]
    public int PersonId { get; set; }

    [Required]
    [StringLength(50,ErrorMessage = "First Name cannot be longer than 50 characters.")]
    [Display(Name= "First Name")]
    public string FirstName { get; set; }

    [StringLength(50, ErrorMessage = "Middle Name cannot be longer than 50 characters.")]
    [Display(Name = "Middle Name")]
    public string MiddleName { get; set; }

    [Required]
    [StringLength(50, ErrorMessage = "Last Name cannot be longer than 50 characters.")]
    [Display(Name = "Last Name")]
    public string LastName { get; set; }
    public PersonType personType {get; set;}

    public Address Address { get; set; }

    [Display(Name = "Full Name")]
    public string FullName
    { 
        get
        {
            return FirstName + " " + LastName;
        }
    }

    [Display(Name = "Full Name w Middle")]
    public string FullNameWMid
    { 
        get
        { 
            return FirstName + " " + MiddleName + " " + LastName;
        }
    }
}

Student Example:

public class Student : Person
{
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:mm-dd-yyyy}", ApplyFormatInEditMode = true)]
    [Display(Name = "Birthday")]
    public DateTime Birthday { get; set; }
    public ICollection<int> ParentList { get; set; }

    public virtual ICollection<Parent> Parents { get; set; }
    public virtual Teacher Teacher { get; set; }


}

Child Model:

public class Parent : Person
{       
    public string EmailAddress { get; set; }
    public ICollection<int> StudentList { get; set;  }

    public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
    public virtual ICollection<Student> Students { get; set; }

}

Address Type

public class Address
{
    public int AddressId { get; set; }
    public string StreetLine1 { get; set; }
    public string StreetLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }

    public Person Person { get; set; }

}
1
0
8/12/2014 12:18:08 AM

Popular Answer

You're going to run into a lot of issues here, I agree. First off, 1:1 connections can only be supported by Entity Framework when they make use of a "shared primary key". This requires that the Address ID and the Parent or Student ID match, and that the address be a foreign key to the other.

I know it appears simple to establish navigation properties for each and have a 1:1 relationship, but you must take into account how this information is stored in the database. In reality, it establishes two distinct 1:many relationships. Additionally, this leads to a situation that EF is unable to handle because there is nothing stopping you from assigning more than one object to the many end.

Since you need to link the address to multiple tables, this inevitably makes things more challenging.

Instead, I would advise constructing an entity called "Person" from which both Student and Parent can deduce, and then using TPH or TPC inheritance to produce separate entities for Student and Parent.

Your Parents and Students will be able to share a single ID as a result, which you can use as your 1:1 shared key with your address entity.

More details are available here:

http://blog.bennymichielsen.be/2011/06/02/entity-framework-4-1-one-to-one-mapping/

1
8/11/2014 4:59:47 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow