Home » .Net FrameworkRSS

CTP5: Adding Parent to Child Association for One of One to Many Relation?

I'm

trying in POCO/code-first to create the following schema:

createtable Customer (
  Id intIDENTITY(1,1) notnullprimarykey,
  Namenvarchar(50) notnull,
  /* More customer detail columns... */
  DefaultShippingContactId intnull
)

createtable Contact (
  Id intIDENTITY(1,1) notnullprimarykey,
  CustomerId intnotnull,
  Namenvarchar(50) notnull,
  /* address/... details */
)
altertable Contact addconstraint Contact_Id_CustomerId foreignkey (customerid) references Customer (Id)
altertable Customer addconstraint Constomer_DefaultShippingContactId_ContactId foreignkey (DefaultShippingContactId) references Contact (Id)

That is: DefaultShippingAddressId can identify one of the customer's contacts to use as a default.

The code first should have entity types like:

class Customer {
 publicint Id { get; set; }
 publicstring Name { get; set; }
 // ...publicvirtual ICollection<Contact> Contacts { get; set; }
 publicvirtual Contact DefaultShippingContact { get; set; }
}

class Contact {
 publicint Id { get; set; }
 publicstring Name { get; set; }
 // ...publicvirtual Customer { get; set; }
}

class Contact : DbContext {

 protectedoverridevoid OnModelCreating(ModelBuilder modelBuilder) {

  What goes here?

 }
}

But everything I try in the fluent interface fails to give me what I want. Even accepting that Customer.DefaultShippingContact is required (because I can't use WithOptional(customer => customer.DefaultShippingContact).WithRequiredDependent(contact => contact.Customer) as it results in the FK in the wrong direction...

Is this scenario possible? If it is, then how?

(Having a IsDefault property on Contact would work, but would require code to validate that only one contact is default per customer.)

 

 

2 Answers Found

 

Answer 1

Richard,

 

You should be able to create a schema of this form with a couple of caveats.  Something like this should put the FKs where you want them:

 

            modelBuilder.Entity<Customer>()

                .HasMany(c => c.Contacts)

                .WithRequired(c => c.Customer)

                .IsIndependent()

                .Map(m => m.MapKey(c => c.Id, "CustomerId"));

           

            modelBuilder.Entity<Customer>()

                .HasOptional(c => c.DefaultShippingContact)

                .WithOptionalDependent();

 

The caveats are:

1.       There is currently no way to change the name of the FK for the second relationship, so it will be called “ContactId” rather than “DefaultShippingContactId”.  We hope to rectify this for RTM.

2.       Since you are not mapping FKs into your model you are using “independent associations”.  Independent associations make certain things like n-tier scenarios, data binding, and concurrency resolution very hard, and also have some quirky behaviors.  Usually it is better to map FKs if possible even though it detracts from the pure OO nature of your classes.

 

Thanks,

Arthur

 

Answer 2

Thanks, that works. Including when extended to a Customer.DefaultBillingContact as well.

Re: Caveat 2: That seems a good reason to include Contact.CustomerId then (and note that it should generally not be used in code).

Re: Caveat 1: Being able to use an explicit property for the FK (and name the key in the db) would be appreciated. Having columns "ContactId" and "ContactId1" doesn't make for supportability or maintainability (or, I expect, happy DBAs).

 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter