Search code examples
c#.netentity-framework-6ef-code-first.net-5

Mapping 1-0..1 Relationship with Navigation Property Without FK


I've got 2 entities with a 1-0..1 relationship between them, but restrictions on what the generated DB schema can look like.

So 1 Vehicle to 0 or 1 RecVehicle entity

I need to be able to have a navigation property from Vehicle to RecVehicle, but without the DB Schema for the Vehicles table having a FK to RecVehicle. The PK of the RecVehicle table should be the Id of the Vehicle entity it relates to.

We are using EF code first

public class Vehicle
{
    [Key]
    public int Id { get; set; }
    
    public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
public class RecVehicle
{
    [Key]
    public int VehicleId { get; set; }
    
    [ForeignKey("VehicleId")]
    public Vehicle Vehicle { get; set; }
}

The generated schema needs to be something like this:

Vehicles [ Id(int, pk, not null), ...] <-- no FK column to RecVehicles

RecVehicles [ VehicleId(int, pk, fk, not null), ...]

Originally what I had tried something like this:

public class Vehicle
{
    [Key]
    public int Id { get; set; }

    [InverseProperty("Vehicle")]
    public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}

but this causes this exception:

Unable to determine the principal end of an association between the types 'Contract.Entities.Vehicle' and 'Contract.Entities.RecVehicle'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

I'm not sure what fluent API relationships to setup to make this work, nor the correct set of data annotations to make this work, or if it's even possible.

Reasoning

  • The reason there is strict limitations on the DB schema is our Data team has a migration/data import process that we can not alter
  • We have an existing code base that uses the navigation property in many places (2 teams, desync in schema) so changing to use a lookup in code requires many changes in the code base that we are trying to avoid.

Solution

  • Ended up being able to get this relationship to work like this:

    public class Vehicle
    {
        [Key]
        public int Id { get; set; }
        
        public virtual RecVehicle RecVehicle { get; set; }
    }
    
    public class RecVehicle
    {
        [Key]
        public int VehicleId { get; set; }
        
        [ForeignKey("VehicleId"), Required] //<--- Required attr fixed the principal/dependent confusion EF was having
        public virtual Vehicle Vehicle { get; set; }
    }