Is it possible to configure relationship between 2 classes just using ids instead of navigational properties?

26 Views Asked by At

I have 2 classes and I want to avoid using navigational properties.

So instead of:

public class A
{
    public int Id { get; private set; }
    public B B { get; private set; }
}

public class B
{
    public int Id { get; private set;}
    public A A { get; private set;}
}

I would like to have something like this:

public class A
{
    public int Id { get; private set; }
    //optional and instead of navigational property
    public int? BId { get; private set; }
}

public class B
{
    public int Id { get; private set;}
    //optional and instead of navigational property
    public int? AId { get; private set;}
}

How to configure reliationship between them so whenever I load instance of A or B from db the foreign id is loaded correctly?

1

There are 1 best solutions below

0
Steve Py On

Your first example implies that the relationship is required as A.B and B.A are not null-able, however if they are optional and you just want to have entities containing the FKs that is perfectly fine and you don't really need to do anything if using schema-first.

One-to-one relationships are mapped one of two ways, either a shared PK, or a Many-to-one with a FK on one side and a unique constraint. So with FK fields, you would either have A.BId or B.AId, not both. The reason you don't have both is that it is impossible to enforce that the B record that A.BId has an AId that points back. A ID #1 could have a BId of 1, but B ID #1 could have an AId of 2.

With that in mind you can set up the null-able FK on one table and map the columns in the entity.

If you want to use code-first then this is also available in EF Core:

builder.Entity<A>
    .HasOne<B>()
    .WithOne<A>()
    .HasForeignKey<A>(a => a.BId) // or .HasForeignKey<B>(b => b.AId)
    .IsRequired(false);

If A holds the BId and you want the AId/A for a given B record you need to query it from the As: (If A holds the FK)

var a = context.As.Where(a => a.BId == bId).Single();

Pick whichever side that stands to serve as the aggregate root more often to hold the FK. Does it make more sense to be reading As and wanting to know their B, or Bs and wanting to know their A.