Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting custom foreign key column name with private field with EFCore

I have the following data model:

public class Foo
{
    public Foo(int barId)
    {
        BarId = barId;
    }

    private int BarId;
    public Bar Bar { get; private set; }
}

public class FooTypeConfig : IEntityTypeConfiguration<Foo>
{
    public void Configure(EntityTypeBuilder<Foo> builder)
    {
        builder.HasOne(x => x.Bar)
            .WithMany()
            .HasForeignKey("BarId");
    }
}

public class Bar
{
    public int Id { get; private set; }
}

This works great and according to my expectations, I have a Foo table containing Id and BarId. My private field BarId and my Bar property are also correctly materialized when reading Foo from the database.

The problem is that I would like to find a way to name my private field, and choose a different name for my database column. I would like to name my property _barId and still choose BarId as my column name in my database.

Is this possible?


I have tried renaming the field in my Foo class and specifying my (now non-conventionally-named) foreign key _barId in my EntityTypeConfiguration

builder.HasOne(x => x.Bar).WithMany().HasForeignKey("_barId");

But this resulted in EF still generating a BarId column, without using it as foreign key to the Bar table...

migrationBuilder.CreateTable(
    name: "Foos",
    columns: table => new
    {
        Id = table.Column<int>(nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        BarId = table.Column<int>(nullable: true),
        _barId = table.Column<int>(nullable: false)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Foos", x => x.Id);
        table.ForeignKey(
            name: "FK_Foos_Bars__barId",
            column: x => x._barId,
            principalTable: "Bars",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
    });

Foo table structure

like image 241
Schaemelhout Avatar asked Dec 03 '17 20:12

Schaemelhout


1 Answers

First off, EF maps database columns and FKs to entity properties, not fields. The properties can be real or as in your case - shadow.

So the following line:

builder.HasOne(x => x.Bar).WithMany().HasForeignKey("BarId");

maps the Bar -> Foo relationship FK to a Foo shadow property called BarId and should stay as it is.

You use the Property method to configure the property type, backing field, column name, type and other attributes. For instance:

builder.Property<int>("BarId") // or int? etc.
    .HasField("_barId")
    .HasColumnName("BarId"); // or BazId or whatever you like 

Just make sure you use one and the same property name when defining it and when specifying the FK. You can also use Entry(entity).Property(propertyName) to get/set the value, mark it as modified etc. as well as EF.Property(entity, propertyName) to access it inside LINQ to Entities queries.

like image 70
Ivan Stoev Avatar answered Jan 04 '23 00:01

Ivan Stoev