Direi che ci vuole un sacco di tempo per conoscere ASP.NET Core per capire come realizzare cose rispetto alle versioni precedenti con webform, ma capisco che ASP.NET Core è più grande e tu sei in grado di costruire soluzioni più complesse.
Sono abbastanza nuovo per ASP.NET Core e sto cercando di capire EF Core e i relativi dati. Sto usando https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro per imparare le basi e creare la mia prima applicazione ASP.NET Core.
Ho un'entità "standard" che può avere più moduli (entità modulo). Le entità condividono un paio di proprietà uguali, quindi le ho ereditate entrambe da una classe master chiamata MasterDocument. Precedentemente chiamato documento.
Standard:
namespace Skjemabasen.Models.Document
{
public class Standard : MasterDocument
{
[Display(Name = "Kategori")]
public virtual Category Category { get; set; }
[Display(Name = "Dokumenter")]
public ICollection<Form> Forms { get; set; }
}
}
Modulo:
public class Form : MasterDocument
{
public Format Format { get; set; }
public virtual Member Assignee { get; set; }
public String Status { get; set; }
[ForeignKey("Standard")]
public int StandardId { get; set; }
public Standard Standard { get; set; }
public ICollection<Customer.Subscription> Subscribers { get; set; }
}
MasterDocument:
namespace Skjemabasen.Models.Document
{
public class MasterDocument : IDocument
{
public int ID { get; set; }
[Required]
[Display(Name = "EStandard")]
[StringLength(50)]
public string EStandard { get; set; }
[Required]
[Column("Betegnelse")]
[Display(Name = "Betegnelse")]
[StringLength(60)]
public string Betegnelse { get; set; }
[Display(Name = "Kommentar")]
public string Comment { get; set; }
}
}
Comprendo che ciò può causare una richiesta circolare o una cancellazione circolare, quindi ho inserito un DeleteBehavior.Restrict
su Standard:
modelBuilder.Entity<Standard>()
.HasOne(d => d.Forms)
.WithMany()
.OnDelete(DeleteBehavior.Restrict);
La mia completa classe di contesto:
namespace Skjemabasen.Data
{
public class SkjemabasenContext : DbContext
{
public SkjemabasenContext(DbContextOptions<SkjemabasenContext> options) :base(options)
{
}
public DbSet<Member> Members { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Standard> Standards { get; set; }
public DbSet<Form> Forms { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Revision> Revisions { get; set; }
public DbSet<Subscription> Subscriptions { get; set; }
public DbSet<MasterDocument> Documents { get; set; }
public IQueryable<Customer> CurrentCustomers
{
get { return Customers.Where(c => c.Inactive == false); }
}
public IQueryable<Customer> InActiveCustomers
{
get { return Customers.Where(c => c.Inactive == true); }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Member>().ToTable("Member");
modelBuilder.Entity<Category>().ToTable("Category");
modelBuilder.Entity<Standard>().ToTable("Standard");
modelBuilder.Entity<Form>().ToTable("Form");
modelBuilder.Entity<Customer>().ToTable("Customer");
modelBuilder.Entity<Revision>().ToTable("Revision");
modelBuilder.Entity<Subscription>().ToTable("Subscription");
modelBuilder.Entity<MasterDocument>().ToTable("Document");
modelBuilder.Entity<Standard>()
.HasOne(d => d.Forms)
.WithMany()
.OnDelete(DeleteBehavior.Restrict);
}
}
}
Quando provo a eseguire l'applicazione ottengo l'errore:
System.ArgumentException: 'Il tipo di entità' System.Collections.Generic.ICollection`1 [Skjemabasen.Models.Document.Form] 'fornito per l'argomento' clrType 'deve essere un tipo di riferimento.' Poiché tutti i moduli devono avere uno standard padre e sia "standard" che "modulo" ereditano da MasterDocument, capisco che ASP.NET Core avverte dell'eliminazione circolare, ma non sono sicuro di come ottenere ciò. L'errore dice qualcosa su ICollection di 'Forms' che non è un tipo di riferimento. Manca qualcosa in 'Standard' in relazione alla relazione tra e 'Form'.
Basato su https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro non riesco a capire cosa mi manca qui.
Suppongo che in realtà non vuoi avere entità polimorfiche ereditando da MasterDocument. Quindi, da quello che vedo, tu vuoi che Form e Standard condividano le stesse proprietà di MasterDocument mentre MasterDocument stesso è un'entità. Se questo è il caso, basta astrarre quelle proprietà in una classe base:
public abstract class MasterBaseDocument
{
public int ID { get; set; }
[Required]
[Display(Name = "EStandard")]
[StringLength(50)]
public string EStandard { get; set; }
[Required]
[Column("Betegnelse")]
[Display(Name = "Betegnelse")]
[StringLength(60)]
public string Betegnelse { get; set; }
[Display(Name = "Kommentar")]
public string Comment { get; set; }
}
public class Form : MasterBaseDocument
{
...
}
public class Standard : MasterBaseDocument
{
...
}
public class MasterDocument : MasterBaseDocument
{
// right now, empty here...
}
Questo dovrebbe risolverlo.
Un altro approccio al modello potrebbe essere l'FK di MasterDocument su Form e Standard. In questo modo non ottieni i campi duplicati sui tavoli.
Ulteriore miglioramento: tenere presente che è possibile ottenere tutte le configurazioni che si utilizzano con gli attributi di FluentAPI. In questo modo le tue lezioni sono tenute e separate dalla roba di EF. Questo aggiunge solo rumore e lo rende molto difficile da leggere. Dovrebbero essere anche esempi su Fluent API su documenti EF.