Po pierwsze, spec. Używamy MVC5, .NET 4.5.1 i Entity framework 6.1.Czy istnieje sposób użycia `dynamic` w drzewie wyrażeń lambda?
W naszej aplikacji biznesowej MVC5 mamy wiele powtarzalnych kodów CRUD. Moim zadaniem jest "zautomatyzowanie" większości z nich, co oznacza wyodrębnienie go do klas bazowych i sprawienie, że będzie można go ponownie wykorzystać. Obecnie mam klasy bazowe dla kontrolerów, modeli widoków i modeli encji EF6.
mój abstrakcyjne klasy bazowej że wszystkie podmioty EF6 dziedziczyć:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public abstract Expression<Func<TSubclass, object>> UpdateCriterion();
}
UpdateCriterion
metoda jest stosowana w AddOrUpdate
metody kontekście bazy danych. Mam ogólny parametr dla podklas, ponieważ UpdateCriterion
musi zwracać wyrażenie lambda, które używa dokładnego typu podklasy, a nie interfejsu lub klasy bazowej. Niezwykle uproszczone podklasa realizacji tej abstrakcyjnej klasy bazowej będzie wyglądać następująco:
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;
}
}
Po tym, w SaveOrUpdate
działania mojego kontrolera bazowej, musiałbym kodu:
public ActionResult Save(TViewModel viewModel)
{
if (ModelState.IsValid)
{
var entityModel = viewModel.ConstructEntityModel();
db.Set<TEntityModel>().AddOrUpdate<TEntityModel>(entityModel.UpdateCriterion(), entityModel);
db.SaveChanges();
}
}
Dzięki temu, podklasy kontrolera bazowego nie muszą same implementować metody, tak jak poprzednio. Teraz wszystko to działa i działa naprawdę dobrze pomimo funkowej składni (to znaczy, class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass>
, poważnie?).
Nadchodzi mój problem. Dla większości jednostek kluczem jest pole ID
, ale dla niektórych nie jest, więc nie mogę generalizować poprawnie z implementacją nadklasy. Na razie każda podklasa jednostki implementuje własną UpdateCriterion
. Ale ponieważ dla większości (90% +) podmiotów e => e.ID
jest prawidłową implementacją, mam dużo duplikacji. Więc chcę przepisać klasę bazową jednostka do czegoś takiego:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
return entity => ((dynamic)entity).ID;
}
}
Intencją jest zapewnienie domyślną implementację, która używa identyfikatora jako klucz i pozwolić podklasy zastąpić go, jeśli użyć innego klucza. Nie mogę używać interfejsu lub klasy bazowej z polem identyfikacyjnym, ponieważ nie wszystkie elementy go mają. Pomyślałem, że będę używał dynamic
do wyciągnięcia pola ID
, ale dostaję następujący błąd: Error: An expression tree may not contain a dynamic operation
.
Więc, jakikolwiek pomysł, jak to zrobić? Czy refleksja będzie działać w bazie UpdateCriterion
?
Dzięki, to było dokładnie to, czego potrzebowałem! – Davor
Och, dodatkowo, czy wiesz, jak dodać wiele pól w tej części ciała? jak 'e => nowy {e.ID, e.Nazwa}'? – Davor
Czy wiesz, jak zbudować 'e => new {e.ID, e.Name}?' Z klasami Expression? – codeworx