Durante la creazione della migrazione viene visualizzato il seguente errore:
Impossibile determinare la relazione rappresentata dalla proprietà di navigazione "Location.NorthLocation" di tipo "Location". Configurare manualmente la relazione o ignorare questa proprietà dal modello.
L'entità Location:
public class Location
{
public Guid Id { get; set; }
public DateTime CreatedWhen { get; set; }
public string CreatedBy { get; set; }
public DateTime ModifiedWhen { get; set; }
public string ModifiedBy { get; set; }
public Guid? NorthLocationId { get; set; }
public virtual Location NorthLocation { get; set; }
public Guid? SouthLocationId { get; set; }
public virtual Location SouthLocation { get; set; }
public Guid? EastLocationId { get; set; }
public virtual Location EastLocation { get; set; }
public Guid? WestLocationId { get; set; }
public virtual Location WestLocation { get; set; }
}
La configurazione del tipo:
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
public DbSet<Location> Locations { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<T>().HasKey("Id");
builder.Entity<T>().Property("Id").ValueGeneratedOnAdd();
builder.Entity<T>().Property("CreatedWhen").HasDefaultValueSql("GETDATE()").ValueGeneratedOnAdd();
builder.Entity<T>().Property("ModifiedWhen").IsRequired();
builder.Entity<T>().Property("CreatedBy").HasMaxLength(50).IsRequired();
builder.Entity<T>().Property("ModifiedBy").HasMaxLength(50).IsRequired();
// Locations
builder.Entity<Location>().HasOne(x => x.NorthLocation).WithOne(x => x.SouthLocation).HasForeignKey(typeof(Location), "NorthLocationId").OnDelete(DeleteBehavior.SetNull);
builder.Entity<Location>().HasOne(x => x.SouthLocation).WithOne(x => x.NorthLocation).HasForeignKey(typeof(Location), "SouthLocationId").OnDelete(DeleteBehavior.SetNull);
builder.Entity<Location>().HasOne(x => x.EastLocation).WithOne(x => x.WestLocation).HasForeignKey(typeof(Location), "EastLocationId").OnDelete(DeleteBehavior.SetNull);
builder.Entity<Location>().HasOne(x => x.WestLocation).WithOne(x => x.EastLocation).HasForeignKey(typeof(Location), "WestLocationId").OnDelete(DeleteBehavior.SetNull);
}
}
Il mio obiettivo è avere un'entità Location che si auto-referenzia con i propri vicini a nord / sud / est / ovest.
Qualcuno può suggerire perché potrei ottenere questo errore?
La configurazione del modello non è corretta perché mappa due delle proprietà di navigazione due volte. Ad esempio SouthLocation
è mappato sia come navigazione inversa per la chiave esterna NorthLocationId
che come navigazione diretta per SouthLocationId
.
Ogni proprietà di navigazione (ovvero NorthLocation
, SouthLocation
, EastLocation
, WestLocation
) può essere mappata su una sola relazione (ovvero su una chiave esterna).
Se cancello la seconda e la quarta riga della parte di configurazione della relazione, il modello sembra funzionare correttamente.
In generale in EF Core proviamo a gestire configurazioni confliggenti lasciando vincere l'ultima configurazione, ma ciò ha alcune limitazioni ed è difficile prevedere cosa può accadere quando si esegue questo codice. Certamente, usando l'anteprima EF Core 2.0 su SQL Server, ho ottenuto un'eccezione diversa (un errore da SQL Server, lamentando dipendenze cicliche nel delta in cascata), quindi è possibile che abbiamo migliorato il modo in cui gestiamo questo scenario.
Ecco il codice:
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
using (var db = new MyContext())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
}
}
}
public class MyContext : DbContext
{
public DbSet<Location> Locations { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"server=(localdb)\mssqllocaldb;database=hey;ConnectRetryCount=0");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Location>().HasKey("Id");
modelBuilder.Entity<Location>().Property("Id")
.ValueGeneratedOnAdd();
modelBuilder.Entity<Location>().Property("CreatedWhen")
.HasDefaultValueSql("GETDATE()")
.ValueGeneratedOnAdd();
modelBuilder.Entity<Location>().Property("ModifiedWhen")
.IsRequired();
modelBuilder.Entity<Location>().Property("CreatedBy")
.HasMaxLength(50)
.IsRequired();
modelBuilder.Entity<Location>().Property("ModifiedBy")
.HasMaxLength(50)
.IsRequired();
modelBuilder.Entity<Location>()
.HasOne(x => x.NorthLocation)
.WithOne(x => x.SouthLocation)
.HasForeignKey(typeof(Location), "NorthLocationId")
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Location>()
.HasOne(x => x.EastLocation)
.WithOne(x => x.WestLocation)
.HasForeignKey(typeof(Location), "EastLocationId")
.OnDelete(DeleteBehavior.Restrict);
}
}
public class Location
{
public Guid Id { get; set; }
public DateTime CreatedWhen { get; set; }
public string CreatedBy { get; set; }
public DateTime ModifiedWhen { get; set; }
public string ModifiedBy { get; set; }
public Guid? NorthLocationId { get; set; }
public virtual Location NorthLocation { get; set; }
public Guid? SouthLocationId { get; set; }
public virtual Location SouthLocation { get; set; }
public Guid? EastLocationId { get; set; }
public virtual Location EastLocation { get; set; }
public Guid? WestLocationId { get; set; }
public virtual Location WestLocation { get; set; }
}
}