Innanzitutto, spec. Usiamo MVC5, .NET 4.5.1 e Entity Framework 6.1.C'è un modo per usare `dynamic` nell'albero di espressione lambda?
Nella nostra applicazione aziendale MVC5 abbiamo un sacco di codice CRUD ripetitivo. Il mio compito è "automatizzare" la maggior parte di esso, il che significa estrarlo nelle classi base e renderlo riutilizzabile. Al momento, ho classi base per controller, modelli di vista e modelli di entità EF6.
La mia classe di base astratta che tutte le entità EF6 ereditano:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public abstract Expression<Func<TSubclass, object>> UpdateCriterion();
}
UpdateCriterion
metodo viene utilizzato in AddOrUpdate
metodo contesto del database. Ho un parametro generico per sottoclassi perché UpdateCriterion
deve restituire un'espressione lambda che utilizza un tipo di sottoclasse esatto, non un'interfaccia o una classe base. Una sottoclasse estremamente semplificata attuazione di questa classe di base astratta sarebbe simile a questa:
public class Worker : BaseEntity<Worker>
{
public int ID { get; set; }
public int Name { get; set; }
public override Expression<Func<Worker, object>> UpdateCriterion()
{
return worker => worker.ID;
}
}
Dopo di che, in SaveOrUpdate
azione del mio controller di base, avrei codice come questo:
public ActionResult Save(TViewModel viewModel)
{
if (ModelState.IsValid)
{
var entityModel = viewModel.ConstructEntityModel();
db.Set<TEntityModel>().AddOrUpdate<TEntityModel>(entityModel.UpdateCriterion(), entityModel);
db.SaveChanges();
}
}
Grazie a ciò, le sottoclassi del controller di base non hanno bisogno di implementare il metodo Save
come hanno fatto prima. Ora, tutto questo funziona e funziona davvero bene nonostante la sintassi funky (intendo, class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass>
, sul serio?).
Ecco il mio problema. Per la maggior parte del campo entità ID
è la chiave, ma per alcuni non lo è, quindi non posso generalizzare correttamente con un'implementazione di superclasse. Quindi per ora, ogni sottoclasse di entità implementa il proprio UpdateCriterion
. Ma poiché la maggior parte delle entità (90% +) e => e.ID
è l'implementazione corretta, ho un sacco di duplicazioni. Quindi voglio riscrivere la classe base all'entità di qualcosa di simile:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
return entity => ((dynamic)entity).ID;
}
}
L'intento è quello di fornire implementazione predefinita che utilizza ID come chiave, e consentire sottoclassi di ignorare che se usano una chiave diversa. Non riesco a utilizzare un'interfaccia o una classe base con campo ID perché non tutte le entità ce l'hanno. Ho pensato di usare dynamic
per estrarre il campo ID
, ma ho il seguente errore: Error: An expression tree may not contain a dynamic operation
.
Quindi, qualche idea su come fare questo? Riflessione funzionerebbe nella base UpdateCriterion
?
Grazie, questo era esattamente quello di cui avevo bisogno! – Davor
Oh, inoltre, sai come aggiungere più campi in quella parte del corpo? come 'e => new {e.ID, e.Name}'? – Davor
Hai imparato come costruire 'e => new {e.ID, e.Name}?' Con le classi di espressione? – codeworx