I have a POCO class that has two one-way unary relationships with another class, both classes share an ancestor. The names of the foreign keys in the generated schema do not reflect the property names. (Properties MainContact and FinancialContact give PersonId and PersonId1 field names).
How can I influence schema generation to generate database column names that match the property names?
The model looks like this:
The code looks like this:
public class CustomerContext: DbContext
{
public DbSet<Organisation> Organisations { get; set; }
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
DbDatabase.SetInitializer(new DropCreateDatabaseAlways<CustomerContext>());
}
}
public abstract class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Person : Customer
{
public string Email { get; set; }
}
public class Organisation : Customer
{
public Person FinancialContact { get; set; }
public Person MainContact { get; set; }
}
The schema looks like this:
druttka's answer below did the job and it's nice to know that it's a CTP5 bug that's behind this. EF also needs the cascade behaviour to be specified and I've used the fluent API to do this following the example in the link given by druttka. Some more good reading from Morteza Manavi here.
The code now is this:
public class CustomerContext : DbContext
{
public DbSet<Organisation> Organisations { get; set; }
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
DbDatabase.SetInitializer(new DropCreateDatabaseAlways<CustomerContext>());
builder.Entity<Organisation>()
.HasRequired(p => p.MainContact)
.WithMany()
.HasForeignKey(p => p.MainContactId)
.WillCascadeOnDelete(false);
builder.Entity<Organisation>()
.Property(p => p.MainContactId)
.HasColumnName("MainContact");
builder.Entity<Organisation>()
.HasRequired(p => p.FinancialContact)
.WithMany()
.HasForeignKey(p => p.FinancialContactId)
.WillCascadeOnDelete(false);
builder.Entity<Organisation>()
.Property(p => p.FinancialContactId)
.HasColumnName("FinancialContact");
}
}
public abstract class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Person : Customer
{
public string Email { get; set; }
}
public class Organisation : Customer
{
public Person FinancialContact { get; set; }
public int FinancialContactId { get; set; }
public Person MainContact { get; set; }
public int MainContactId { get; set; }
}
Which now gives the far more suitable database:
EF Code First uses, by default, convention over configuration. However, you can set explicit alternatives by overriding DbContent.OnModelCreating. Many examples here, courtesy of ScottGu.
EDIT
So in CTP5, MapSingleType went away as described here. The following works for simple string properties, but not for your Organisation to Person relationships. I'm curious and plan to keep looking at it, but in the meantime, maybe this will get your started or someone else can complete the answer.
public class Person : Customer
{
[Column(Name="EmailAddress")]
public string Email { get; set; }
}
EDIT 2
Ok, this gets it. Found the answer here. Disclaimer: I've only verified that the database schema is created as expected. I have not tested that seeding data or further CRUD operations work as expected.
public class Organisation : Customer
{
[Column(Name = "FinancialContact")]
public int? FinancialContactId { get; set; }
[ForeignKey("FinancialContactId")]
public Person FinancialContact { get; set; }
[Column(Name = "MainContact")]
public int? MainContactId { get; set; }
[ForeignKey("MainContactId")]
public Person MainContact { get; set; }
}