Ho il seguente schema (abbreviato in codice pertinente)
class Person
{
public int Id {get;set;}
public string Name {get;set;}
public ICollection<MetaData> MetaData {get;set;}
}
class Car
{
public int Id {get;set;}
public string Make {get;set;}
public ICollection<MetaData> MetaData {get;set;}
}
class Building
{
public int Id {get;set;}
public string Address {get;set;}
public ICollection<MetaData> MetaData {get;set;}
}
class MetaData
{
public int Id {get;set;}
public string CLRType {get;set;}
public string Value {get;set;}
// These two fields together form a connection to the other entities
public int Key {get;set;} // the PK of the connected entity
public string Type {get;set;} // nameof(Entity)
}
Come posso rappresentarlo in EF Core?
Utilizzo di OwnsMany
crea una tabella per tipo + connessione tipo metadati Se provo a utilizzare TPH, la tabella dei metadati finisce con campi aggiuntivi per entità connessa
Nessuna di queste soluzioni è l'ideale per me. Non ho bisogno di restrizioni nel database, voglio solo un modo per esprimere questa relazione in modo tale che EF Core sarà in grado di idratare i miei modelli Anche se devo fornire sql manualmente (anche per letture e scritture) che sarebbe praticabile
Se ciò non è possibile con le API esistenti fornite, esiste un modo per scrivere estensioni da solo che farà ciò di cui ho bisogno?
Stai mescolando due forme di relazioni. Puoi avere relazioni di tipo sicuro e replicare le chiavi esterne sulla tua classe Metadata (non dimenticare di aggiungere vincoli univoci)
class MetaData
{
public int Id {get;set;}
public string CLRType {get;set;}
public string Value {get;set;}
public int PersonId {get;set;}
public Person Person {get;set;}
public int CarId {get;set;}
public Car Car {get;set;}
public int BuildingId {get;set;}
public Person Building {get;set;}
}
O tenerlo accoppiato in modo lasco e fare i giunti a mano
class Car
{
public int Id {get;set;}
public string Make {get;set;}
}
// not mapped in the database, just used for display purposes
class CarViewModel
{
public int Id {get;set;}
public string Make {get;set;}
}
var carIds = new [] { 1, 2, 3 };
// we use 2 contexts here so we can query both tables at the same time.
// otherwise Task.WhenAll(...) would throw an exception.
// you should also disable change tracking to improve speed.
var carsTask = context1.Cars
.Where(c => carIds.Contains(c.Id))
.ToListAsync();
var metadataTask = context2.Metadata
.Where(m => carIds.Contains(m.Key) && m.Type == "Car")
.GroupBy(m => m.Key)
.ToDictionaryAsync(g => g.Key, g => g.ToList());
await Task.WhenAll(carsTask, metadataTask).ConfigureAwait(false);
var cars = carsTask.Result
.Select(c => new CarViewModel
{
Id = c.Id,
Make = c.Make,
Metadata = metadataTask.Result.TryGetValue(c.Id, out var m) ? m : Array.Empty<Metadata>(),
})
.ToList();
O hanno tabelle separate per i metadati
abstract class MetaData
{
public int Id {get;set;}
public string CLRType {get;set;}
public string Value {get;set;}
}
class CarMetaData : MetaData
{
public int CarId {get;set;}
public Car Car {get;set;}
}
class Car
{
public int Id {get;set;}
public string Make {get;set;}
public ICollection<CarMetaData> MetaData {get;set;}
}
La versione più adatta a te dipende dalle tue e dalle tue esigenze aziendali specifiche.