Sto imparando Automapper e EF Core e sono incappato in un problema, mentre provavo a modellare la proprietà get-only, che è calcolata in base alla proprietà di navigazione. Sto avendo due modelli:
public class Parent
{
public int Id {get;set;}
public string Name {get;set;}
public ICollection<Child> Childs {get;set;}
public int WantedChildCount {get{return Childs?.Count(c=>c.Type!=1)??0;}
}
public class Child
{
public int Id {get;set;}
public string Name {get;set;}
public int Type {get;set;}
}
Un DTO:
public class VM
{
public string Name{get;set;}
public int WantedCount{get;set;}
}
E provando ad automatizzare VM da Parent come:
var c = context.Parents.Include(p => p.Childs).ProjectTo<VM>().FirstOrDefault();
Automapper configurato in questo modo:
Mapper.Initialize(cfg=>
cfg.CreateMap<Parent, VM>()
.ForMember(d=>d.WantedCount, o => o.MapFrom(s=>s.WantedChildCount));
Il problema è che nel campo della VM risultante WantedCount non è popolato. Nei log ho trovato un messaggio
The Include operation for navigation: 'p.Childs' was ignored because the target navigation is not reachable in the final query results.
È semplice dividere questa operazione in due distinti: prima prendi Parent, quindi Mapper.Map. Inoltre, potrebbe funzionare quando si cambia Mappa in questo modo:
cfg.CreateMap<Parent, VM>()
.ForMember(d=>d.WantedCount, o => o.MapFrom(s=>s.Childs(c=>c.Type!=1));
Ma in questo modo ignorerò totalmente la proprietà get-only nel modello. Mi piacerebbe capire qual è il problema, e come potrei risolverlo.
O forse dovrei anche spostare in qualche modo il calcolo sul lato DB? Ma vorrei evitare di memorizzare questa proprietà nel database.
ProjectTo
è l'equivalente Auto Mapper di Queryable.Select
, quindi la query risultante ricade nella categoria Include ignorati core di EF.
Come al solito con le IQuerable<T>
, dovresti usare un'espressione esplicita che può essere mappata su SQL, ad esempio qualcosa come questo accesso direttamente alla proprietà di navigazione
o.MapFrom(s => s.Childs.Count(c => c.Type != 1))
Nota che mentre questo dovrebbe popolare il WantedChildCount
desiderato, l' Include
verrà comunque ignorata.