burnersk
burnersk

Reputation: 3480

How to define a second Entity Framework Core relationship to the same foreign key?

I have the following entity relation diagram, I have to translate to a C# model, later used within an ASP.NET Core 3.1 web application and handled by Entity Framework Core.

entity relation diagram

There are two entities (Product, and ProductVersion). A Product may have none, one or multiple ProductVersion; this relation is called Versions and Product (the right side of the diagram). A Product may also have none or one ProductVersion which represent the current version; this relation is called CurrentVersion and Product (the left side of the diagram).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.InMemory;

public static class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello, World!");

        var optBuilder = new DbContextOptionsBuilder<MyContext>();
        optBuilder.UseInMemoryDatabase("MyContext");
        MyContext context = new MyContext(optBuilder.Options);
        context.Add(new Product { Name = "First Product" });
    }
}

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options)
         : base(options) { }

        public DbSet<Product> Products { get; set; }

        public DbSet<ProductVersion> ProductVersions { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Product>().HasOne(p => p.CurrentVersion).WithOne(pv => pv.Product);
            modelBuilder.Entity<Product>().HasMany(p => p.Versions).WithOne(pv => pv.Product);
        }
}

public class Product
{
    [Key]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public Guid CurrentVersionId { get; set; }

    [ForeignKey("CurrentVersionId")]
    public virtual ProductVersion CurrentVersion { get; set; }

    [ForeignKey("ProductId")]
    public virtual List<ProductVersion> Versions { get; set; }
}

public class ProductVersion
{
    [Key]
    public Guid Id { get; set; }

    public Guid ProductId { get; set; }

    public Version Version { get; set; }

    public virtual Product Product { get; set; }
}

Here is a .NET Fiddle link for quick experiments: https://dotnetfiddle.net/r1bhGs

The error message is the following:

Unhandled exception. System.InvalidOperationException: Cannot create a relationship between 'Product.Versions' and 'ProductVersion.Product', because there already is a relationship between 'ProductVersion.Product' and 'Product.CurrentVersion'. Navigation properties can only participate in a single relationship.

Is there really no way around a duplicate field for ProductVersion, lets call it CurrentVersionProductId, or is there a fluent solution to this?


In a second attempt, I tried to implement only a CurrentProduct navigational property.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasOne(p => p.CurrentVersion).WithOne(pv => pv.CurrentProduct);
        modelBuilder.Entity<Product>().HasMany(p => p.Versions).WithOne(pv => pv.Product);
    }
public class Product
{
    [Key]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public Guid CurrentVersionId { get; set; }

    [ForeignKey("CurrentVersionId")]
    public virtual ProductVersion CurrentVersion { get; set; }

    [ForeignKey("ProductId")]
    public virtual List<ProductVersion> Versions { get; set; }
}

public class ProductVersion
{
    [Key]
    public Guid Id { get; set; }

    public Guid ProductId { get; set; }

    public Version Version { get; set; }

    public virtual Product Product { get; set; }

    public virtual Product CurrentProduct { get; set; }
}

Here is the .NET Fiddle for this code: https://dotnetfiddle.net/zkZwgF

However, I ran into the following error:

Unhandled exception. System.InvalidOperationException: The entity type 'Version' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'.

Why have to be Version the primary key, when Id is already marked as the primary [Key]?

Upvotes: 0

Views: 1084

Answers (1)

Guru Stron
Guru Stron

Reputation: 142038

Try adding to the latter:

modelBuilder.Entity<ProductVersion>().OwnsOne(p => p.Version);

Owned Entity Types

Your Version property is of type Systme.Version which EF recognizes as a navigation property and it can't determine a primary key for this entity, cause you have not defined it in any way.

Upvotes: 1

Related Questions