I am trying to model what I think is quite a basic scenario, but I can’t get my head around the correct way to define it in EF Code First 5.
I have three classes:
Employee
Postal Address
Contact Telephone Number
The rules are thus:
- A Postal Address can be standalone
- A Contact Telephone Number can be standalone
- Optionally, an Employee can have a “Home” Postal Address
- An Employee can have zero or more Contact Telephone Numbers
If I model this in SQL, I end up with four tables;
- PostalAddress
- ContactTelephoneNumber
- Employee
- EmployeeContactTelephoneNumber (bridge table)
By looking through the answers here on SO, I can produce something similar to my SQL model in Code First with the exception that I have to have an Employee navigation property on PostalAddress and an Employees navigation property on ContactTelephoneNumber. This goes against my business rules, because neither PostalAddress nor ContactTelephoneNumber will always be refered to be an Employee. For example, I could later add a Premises class which would also have a PostalAddress.
By way of code examples, what I have now resembles the following:
public class Employee
{
public int EmployeeID {get;set;}
public virtual PostalAddress? HomeAddress {get;set;}
}
public class PostalAddress
{
public int PostalAddressID {get;set;}
public string Address {get;set;} // It's not actually a string - this is for brevity!
}
public class ContactTelephoneNumber
{
public int ContactTelephoneNumberID {get;set;}
public string TelephoneNumber {get;set;} // It's not actually a string - this is for brevity!
}
I’m trying to define my relationships using the Fluent API rather than Annotations, to ensure my presentation layer remains unaware of Entity Framework when consuming these classes. My mapping currently resembles the following – is this “correct”?
public class EmployeeMap : EntityTypeConfiguration<Employee>
{
public EmployeeMap()
{
this.HasOptional(e => e.HomeAddress).WithOptionalDependent(p => p.Value).Map(m => m.MapKey("PostalAddressID"));
}
}
This doesn’t compile; I get:
The type ‘PostalAddress?’ must be a reference type in order to use it as parameter ‘TTargetEntity’ in the generic type or method ‘System.Data.Entity.ModelConfiguration.EntityTypeConfiguration.HasOptional(System.Linq.Expressions.Expression>)’
Additionally, I don’t like that I’m passing “PostalAddressID” as a string constant into the call to MapKey().
Please could someone highlight the error of my ways? I’ve been searching for the past 3 hours to no avail!
Edit: I should mention that once I understand this part I’ll try and address the Employee>ContactTelephoneNumbers situation separately.
You have declared HomeAddress as a value type, specifically as a
Nullable<T>.Remove the ? from the declaration (reference types allow null, and therefore do not need to be wrapped in the Nullable struct).
To specify the mapping, I think you can use this:
You will also need to add the HomeAddressID property to the Employee class.