Reputation: 21
I need some help here. I am having major problems creating my models based off of my ideas for my project. To simplify things, I have a Parent table, a Student table, and an Address table. So, each Parent record, can have multiple Students and only a single address. Each Student record, can have multiple Parents and only a single address. Logically, I really can't assume that the students address is the same as the parents address, since there can be a student with parents living in different locations. So, I would like to be able to have an address for student as well as an address for each parent. So, I basically envision this DB layout to come down to an Address table, with AddressID, street, city, state, zip.. And then a student table, with StudentID, name, addressID. And then a Parent table with ParentID, name, addressID. And then a Parent_Student reference table, with StudentID and ParentID.
So, any thoughts on how I can implement this? I created my Address Model with just the address information and ID. I created my Student model with ID, name, Virtual Address, and Virtual ICollection Parent. And then created my Parent model with ID, name, Virtual Address, and Virtual ICollection. When I try to create my Student controller via New->Scaffolded Item, I get an error about VS unable to determine the principal end of an association between the types Parent and Address.
I'm assuming this has to do with the fact that an address record willhave a foreign Key to either Parent or Student, but not both. I'm pretty new to this whole code-first approach, so any insight would be greatly appreciated. Thanks in advance!
EDIT: Adding UPDATED Code
PERSON 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 Model:
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; }
}
Parent 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 Model:
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; }
}
Upvotes: 0
Views: 2234
Reputation: 50
First of all I don't think the naming is appropriate. Associating Parent with Student gives no meaning, I think it should be Parent and Child. And providing ID property as primary key in each of them makes it quite difficult to maintain. However, let us try to implement it your way.
Make a Class as Person with common properties as ID, Full Name and First Name and Last Name, House Number other general information. Doing this would give one primary Key (ID) and one foreign Key(House Number). Now you have got 1:1 relation with Address class.
In above models for Student and Parent class given by you, I find no such property to associate a student with its parent and the vice versa. Now you create classes Parent and Student such as : Parent class has an integer collection property for ID ( ParentOfStudentsList) and similarly, Student class has an integer collection property to hold all the IDs of parents, associated with( StudentOfParentsList), doing this allows you to have One to many and many to one relationship between Parent and Student.
Note: Do derive Person class in Parent and Student. I hope this solution works for you.
Upvotes: 0
Reputation: 93444
Yeah, you're going to have a number of problems here. First, Entity Framework only supports 1:1 relationships when they use a "shared primary key". That means the Address ID and the Parent or Student ID have to be the same, and the address has to be a foreign key to the other.
I know it seems easy to just create navigation properties to each and you should have a 1:1, but you have to consider how this gets created in the database. What it actually creates is two separate 1:many relationships. And, since there is nothing to prevent you from assigning more than one entity to the many end, this results in a situation EF doesn't support.
This of course makes things difficult since you have several tables to link the address to.
I would suggest instead creating a "Person" entity which both Student and Parent derive from, then use TPH or TPC inheritance to create your Student and Parent unique entities.
This allows your Parents and Students to share a common ID, which you can then use as your 1:1 shared key with your address entity.
You can find out more here:
http://blog.bennymichielsen.be/2011/06/02/entity-framework-4-1-one-to-one-mapping/
Upvotes: 1