EF Code First 4.1 - How to configure one to many relationship with default

前端 未结 1 2016
醉酒成梦
醉酒成梦 2020-12-17 02:18

I have a Customer entity which references a collection of Addresses. The complication here is that I want to be able to identify a particular address as the default address

相关标签:
1条回答
  • 2020-12-17 02:59

    I don't understand what EF is talking there about "not exposed foreign keys" in the exception. I would consider the inner exception as the important part:

    Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.

    I think the problem in your model is that you have a mutual dependency between Customer and Address: An address needs a customer (you have marked it as required in your mapping code) and on the other hand a customer needs an address (the default address is required both due to the non-nullable foreign key and due to your mapping code). So, EF doesn't know which entity to save first in your example code - the default address or the customer? Both entities need the primary key of the other to be saved with valid FK contraints.

    The easiest solution I can see is to make the default address optional in your model and then save twice (I omit the mappings which work by convention anyway):

    public class Customer
    {
        private ICollection<Address> m_Addresses;
    
        public Customer() { Addresses = new List<Address>(); }
    
        public int Id { get; set; }
        public string CompanyName { get; set; }
        public virtual ICollection<Address> Addresses { get { ... } set { ... } }
        public Address DefaultAddress { get; set; }
        public int? DefaultAddressId { get; set; } // FK for optional relationship
    }
    
    public class Address
    {
        public int Id { get; set; }
        public string Town { get; set; }
        public Customer Customer { get; set; }
    }
    
    // ...
    
    public class CustomerConfiguration : EntityTypeConfiguration<Customer>
    {
        public CustomerConfiguration() : base()
        {
            Property(p => p.CompanyName)
                .HasColumnName("Name")
                .IsRequired();
    
            HasMany(c => c.Addresses)
                .WithRequired(a => a.Customer)
                .Map(x => x.MapKey("CustomerId"));
        }
    }
    
    public class AddressConfiguration : EntityTypeConfiguration<Address>
    {
        public AddressConfiguration() : base()
        {
            Property(p => p.Town)
                .HasColumnName("Town")
                .IsRequired();
        }
    }
    

    And then your program would look like this:

    static void Main(string[] args)
    {
        Customer headOffice = new Customer();
        headOffice.CompanyName = "C1";
    
        Address address = new Address();
        address.Town = "Colchester";
        headOffice.Addresses.Add(address);
    
        address = new Address();
        address.Town = "Norwich";
        headOffice.Addresses.Add(address);
    
        //headOffice.DefaultAddress = address;
        //We don't set the default address here as SaveChanges would throw an
        //exception. But because it is optional now we are allowed to leave it null.
    
        MyContext context = new MyContext(ConnectionString);
        context.Customers.Add(headOffice);
        context.SaveChanges();
    
        headOffice.DefaultAddress = address; // headoffice and address have now PKs
        context.SaveChanges(); // Updates headoffice in the DB with default address
    }
    

    This double SaveChanges is ugly, but I don't see another way.

    0 讨论(0)
提交回复
热议问题