Reputation: 3480
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.
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
Reputation: 142038
Try adding to the latter:
modelBuilder.Entity<ProductVersion>().OwnsOne(p => p.Version);
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