In the snippet below you can see that a customer has an address property.
public class Customer { public Customer() { Address = new Address(); } public Guid Id { get; set; } public string Name { get; set; } public Address Address { get; set; } public Guid AddressId { get; set; } } public class Address { public Guid Id { get; set; } public string City { get; set; } public string Country { get; set; } public string Street { get; set; } } |
The database that gets generated though defines this as a one to many relationship.
Which is not what you’re expecting, or is it? I haven’t defined any restrictions on the address class so indeed an address could be shared between multiple customers. Let’s change that.
public class Customer { public Customer() { Address = new Address(); } public Guid Id { get; set; } public string Name { get; set; } public Address Address { get; set; } } public class Address { public Guid Id { get; set; } public string City { get; set; } public string Country { get; set; } public string Street { get; set; } [Required] public Customer Customer { get; set; } } |
I’ve added a navigation property from Address to Customer and marked the Customer property as required. This basically is telling EF that there is a one to one mapping between the two and the primary key of the customer should be used in the relationship. The primary key of the customer will also become the primary key of the address. If you did not add the required attribute you’ll get an invalidoperationexception saying that it’s unable to determine the principal end of an association.
You can also use the fluent api.
public class CustomerContext : DbContext { public IDbSet<Customer> Customers { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Address>().HasRequired(x => x.Customer); base.OnModelCreating(modelBuilder); } } |
They both result in the same database structure.
What if both ends are required? A customer always has an address and an address always has a customer. Marking both ends as required will again result in the same exception as before.
In order to model this you have to use the fluent api and there are two ways to achieve the desired result.
public class CustomerContext : DbContext { public IDbSet<Customer> Customers { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Address>() .HasRequired(x => x.Customer) .WithRequiredDependent(x => x.Address); base.OnModelCreating(modelBuilder); } } |
I’m saying here that the address entity has a required customer property and that the customer class is actually in charge, MSDN reference.
Another way to achieve the same result:
public class CustomerContext : DbContext { public IDbSet<Customer> Customers { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Address>() .HasRequired(x => x.Customer) .WithRequiredDependent(); modelBuilder.Entity<Customer>() .HasRequired(x => x.Address) .WithRequiredPrincipal(); base.OnModelCreating(modelBuilder); } } |
MSDN link on WithRequiredPrincipal.
You saw that the WithRequiredPrincipal and Depedant actually have one taking a lambda and one with no arguments. This allows you to exclude a navigation property and still get a proper one to one mapping. Which brings me back to my starting point.
public class Customer { public Customer() { Address = new Address(); } public Guid Id { get; set; } public string Name { get; set; } public Address Address { get; set; } } public class Address { public Guid Id { get; set; } public string City { get; set; } public string Country { get; set; } public string Street { get; set; } } public class CustomerContext : DbContext { public IDbSet<Customer> Customers { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Customer>() .HasRequired(x => x.Address) .WithRequiredPrincipal(); base.OnModelCreating(modelBuilder); } } |
Good post. Thank you very much, Benny!
Thank you, Benny, your post helped a lot to resolve one problem I had in my EF code. Appreciate it!
Is there a way to use data annotations instead of the fluent API in this scanario? (0/1-1)
thank you. nice decription much appreciated. tyty
How to display on the web i.e i mean calling the function in the Controller action explain that also..given a Customer Id it should display the both related rows from Customer and Address
That’s fine except Address never gets saved to the database since there is no DBSet for it in the Context (first of the both ends required scenarios, I never tried the other).
Hi, i`v used this approeach but when i see in database there is not a column created customer for Address.
in fact when i want to retrive data it says ” null reference exception”.
may you help me?
Clean concise explanations.. Thanks
This helped me, thanks!
Thank you very much!
Thanks. And if i need to build one-to-one realationship between 2 tables with 2 keys ?
For Example
Customers (Id1 (key),id2(key),Name)
Addresses (Id1 (key),id2(key),City,Country,Street)
What about that case if I need two Adress field for the customer.
Customer
—> PrivateAdress
—> FirmAdress
??
What if I don’t want bidirection navigation e.g. Customer is my aggregate root nor foreign key properties like AddressId?
What if the Address navigation property on Customer class is optional? Is there a way to do this using attributes?
Thank you Benny.
Fucking Awesome man… Thanks a lot…
hi .
i have a problem. please help me .
how can i have a one-to-one relationship between a primarykey from a product table (for example) and non-primarykey from information (for example) in code first ?