Using Entity Framework 5
So I have a Customer. The Customer could have many Addresses, but at least one. One of the addresses would also be set as the primary address (required). I tried various mappings, but so far I get an error on build or when I seed the database.
Customer:
public class Customer
{
public int CustomerId { get; set;}
public String CustomerName { get; set; }
public int PrimaryAddressId { get; set; }
public virtual CustomerAddress PrimaryAddress { get; set; }
public virtual ICollection<CustomerAddress> CustomerAddresses { get; set; }
}
Address:
public class CustomerAddress : Address
{
public int CustomerAddressId { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
This part of my mapping is working correctly. It is on CustomerAddress.
this.HasRequired(c => c.Customer)
.WithMany(d => d.CustomerAddresses)
.HasForeignKey(c => c.CustomerId);
But how do I specify the correct mapping for setting PrimaryAddress in Customer? Or is it the wrong approach?
Thanks
EDIT – Using both Arnolds and LueTM’s answers:
This code is now working.
Customer:
public class Customer
{
public int CustomerId { get; set;}
public String CustomerName { get; set; }
// public int PrimaryAddressId { get; set; } created in mapping
public virtual CustomerAddress PrimaryAddress { get; set; }
public virtual ICollection<CustomerAddress> CustomerAddresses { get; set; }
}
Address:
public class CustomerAddress : Address
{
public int CustomerAddressId { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
Customer mapping:
modelBuilder.Entity<Customer>
.HasOptional(c => c.PrimaryAddress)
.WithOptionalDependent().Map(m => m.MapKey("PrimaryAddressId"));
modelBuilder.Entity<Customer>
.HasMany(c => c.CustomerAddresses)
.WithRequired(c => c.Customer)
.HasForeignKey(c => c.CustomerId)
.WillCascadeOnDelete(false);
And I use a repository to make sure that a new address is created first, saved, and then also set as primary and saved again. The repository makes sure the primary is “required”.
Since you don’t show the exception, I have to assume that you ran into a chicken-egg problem.
If you set
PrimaryAddressas a required property EF must have an existing address Id to establish the foreign key (setPrimaryAddressIdinCustomer). However, sinceAddressrequires aCustomeryou cannot store an address before its customer. And if you try to save an address and a customer in one take, EF can not determine the correct order of inserts, because it needs to insert both objects with the generated Id of the other object.So either
AddressorCustomermust have an optional foreign key.I would make
Customer.PrimaryAddressIdoptional:Now you can store addresses and assign a primary address to a customer in separeate transactions. But you need business logic to ensure that a
Customeralways has a primary address.If you want to save cutomers and addresses in one transaction, an approach could be to add an
IsPrimaryproperty (bool) toCustomerAddressand ensure that always exactly one address hastrue.