Home > Back-end >  Entity Framework Optional One-To-One with Joining Table
Entity Framework Optional One-To-One with Joining Table

Time:08-25

I have existing tables Assets and DownPayments, and I want to join them with AssetDownPayments:

Database diagram showing Assets joined to DownPayments through a joining table

Asset.cs:

[InverseProperty(nameof(AssetDownPayment.Asset))]
public virtual AssetDownPayment AssetDownPaymentAssignment { get; set; }

DownPayment.cs

[InverseProperty(nameof(AssetDownPayment.DownPayment))]
public virtual AssetDownPayment AssetDownPaymentAssignment { get; set; }

AssetDownPayment.cs

public class AssetDownPayment
{
    public AssetDownPayment() { }

    [Key, Column(Order = 0)]
    [Index(IsUnique = true)]
    [ForeignKey(nameof(Asset))]
    public int AssetID { get; set; }
    [InverseProperty(nameof(Models.Asset.AssetDownPaymentAssignment))]
    public virtual Asset Asset { get; set; }

    [Key, Column(Order = 1)]
    [Index(IsUnique = true)]
    [ForeignKey(nameof(DownPayment))]
    public int DownPaymentID { get; set; }
    [InverseProperty(nameof(Models.DownPayment.AssetDownPaymentAssignment))]
    public virtual DownPayment DownPayment { get; set; }
}

I'm attempting to build a migration for adding AssetDownPayment and the error I get is:

Unable to determine the principal end of an association between the types 'DAL.Models.AssetDownPayment' and 'DAL.Models.Asset'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

CodePudding user response:

That is not a one-to-one relationship, that is a many-to-many.

For a one-to-one (or one-to-zero-or-one) you do not use a joining table:

[Assets]
AssetId (PK, Identity)
Amount
Description

[Downpayment]
AssetId (PK)
Amount
Description

Then when configuring the relationship:

modelBuilder.Entity<Asset>()
    .HasOptional(a => a.Downpayment)
    .WithRequired(d => d.Asset);

Assuming that an asset may, or may not have a downpayment, but every downpayment should be associated to an Asset. One-to-one relationships default to using the PK on both tables to join the records. Asset "owns" the PK and can be set up with an Identity. Downpayment should be set up with [DatabaseGenerated(DatabaseGeneratedOption.None)] as it will be given it's ID based on the asset it is associated with.

  • Related