Search code examples
c#.netentity-framework-coreef-core-6.0

Create a relationship between two classes with different property names


Using EF 6 and given the following classes:

public class A: 
{
    public int Id{ get; set; }

    public string PropA {get; set;}
    public string PorpB {get; set;} 

    public List<B> Bs {get; set;}
}

public class B: 
{
    public int Id {get; set;}
    public string PropB {get; set;}
    public string PorpC {get; set;} 
}

I want to create a relation of one A to many Bs with the problem of having different names in the composite Principal Key:

While property PropB in class A corresponds to PropB in class B, PropA in class A has to correspond with PropC in class B.

I have tried with the model builder but I can't find a place to map the names of class A to class B:

modelBuilder.Entity<A>(a=>
{
    a.HasKey(a => a.Id);
    a.HasMany(a=> a.Bs).WithOne().HasPrincipalKey("PropA", "PropB"); <= Can't find PropA in classB
});

How can I do that?

Note: I can't modify the database and creating the relationship with the Id atribute is not an option.


Solution

  • Sure! Add a .HasForeignKey call (and preferentially use the lambda versions of the fluent configuration methods).

    modelBuilder.Entity<A>(a =>
    {
        a.HasKey(a => a.Id);
        a.HasMany(a => a.Bs).WithOne()
            .HasPrincipalKey(a => new { a.PropA, a.PropB })
            .HasForeignKey(b => new { b.PropC, b.PropB });
    });
    

    And the resulting table definitions:

    CREATE TABLE [A] (
      [Id] int NOT NULL IDENTITY,
      [PropA] nvarchar(450) NOT NULL,
      [PropB] nvarchar(450) NOT NULL,
      CONSTRAINT [PK_A] PRIMARY KEY ([Id]),
      CONSTRAINT [AK_A_PropA_PropB] UNIQUE ([PropA], [PropB])
    );
    CREATE TABLE [B] (
      [Id] int NOT NULL IDENTITY,
      [PropB] nvarchar(450) NOT NULL,
      [PropC] nvarchar(450) NOT NULL,
      CONSTRAINT [PK_B] PRIMARY KEY ([Id]),
      CONSTRAINT [FK_B_A_PropC_PropB] FOREIGN KEY ([PropC], [PropB])
          REFERENCES [A] ([PropA], [PropB]) ON DELETE CASCADE
    );
    

    Note that the reference to PropA and PropB in class A causes EF to generate a unique index over these properties, in order to make the identification succeed. (Or, when not using migrations, it makes EF assume that the combination is unique. )

    In other words, for EF the two properties are an alternate key (hence the AK prefix in the index). This also means that, just as primary key properties, you won't be able to modify these properties using EF, so this is a design decision that requires careful consideration.