Grenville
Grenville

Reputation: 245

Configuring one-to-many and one-to-one relationship in Entity Framework Core

I'm quite new to Entity Framework and am picking it up with the Core version. I'm trying to understand how to customise model relationships.

My basic model is that I have a Company entity, and a Contact entity. A Company can have many Contacts. A company can a KeyContact, which must be one of the associated contacts, but is not required.

Thus there is a One to Many relationship, but also a One to One relationship. I've tried to implement this as below (removed most other fields for clarity);

public class Company
{
    public int Id { get; set; }
    public int? KeyContactId { get; set; }
    public ICollection<Contact> Contacts { get; set; }
    public Contact KeyContact { get; set; }
}

public class Contact
{
    public int Id { get; set; }
    public int CompanyId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Company Company { get; set; }
}

It fails to add this migration with the message;

Unable to determine the relationship represented by navigation property 'Company.Contacts' of type 'ICollection'. Either manually configure the relationship, or ignore this property from the model.

I can kinda see why it's complaining about this, but I'm not sure if there's a way with the model builder I can configure this, or whether it's an invalid pattern. My model builder is currently just basic;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Company>().ToTable("Company");
    modelBuilder.Entity<Contact>().ToTable("Contact");
}

I know I could just have a flag to say IsKeyContact in the contact table, but I like the idea of having the navigation property in the company entity. So I'm wondering how sugary Entity can be.

Any help much appreciated.

Thanks,

Nick

Upvotes: 7

Views: 3028

Answers (1)

Gero Iwan
Gero Iwan

Reputation: 83

The exception is avoided by adding the following line to the OnModelCreating method:

modelBuilder.Entity<Company>().HasMany(p => p.Contacts).WithOne(d => d.Company).HasForeignKey(d => d.CompanyId);

This configures the Company.Contacts-Contact.Company relation. By default, the Company.KeyContact relation is configured as if the following line would be within the OnModelCreating method:

modelBuilder.Entity<Company>().HasOne(e => e.KeyContact).WithMany().HasForeignKey(e => e.KeyContactId);

Hence a Contact can be the KeyContact of more than one Company. In order to ensure that a Contact can be the KeyContact of at most one Company the Company.KeyContact relation could be configured by the following line within the OnModelCreating method:

modelBuilder.Entity<Company>().HasOne(e => e.KeyContact).WithOne().HasForeignKey<Company>(e => e.KeyContactId);

But note: This will not ensure that the KeyContact is a member of the Contacts.

Upvotes: 4

Related Questions