2013-02-25 14 views
5

Podczas dodawania kontrolera do modelu, wygenerowane działania będą wyglądać takAutomatycznie przechodzą jednostki do działania kontrolera

public ActionResult Edit(int id = 0) 
{ 
    Entity entity = db.Entities.Find(id); 
    if (entity == null) 
    { 
     return HttpNotFound(); 
    } 
    return View(entity); 
} 

Teraz w moim przypadku podjęcia id ciąg, który można mapować do DB identyfikatorów w kilku sposoby, tworząc kilka linii kodu dla odzyskania właściwego obiektu. Skopiowanie & wklejenia tego kodu do każdej akcji, która pobiera identyfikator w celu pobrania obiektu, wydaje się bardzo nieeleganckie.

Umieszczenie kodu identyfikacyjnego w prywatnym funkcji regulatora zmniejsza ilość duplikatu kodu, ale ja wciąż pozostaje tym:

var entity = GetEntityById(id); 
if (entity == null) 
    return HttpNotFound(); 

Czy istnieje sposób, aby przeprowadzić wyszukiwanie w atrybucie i przekazać podmiot do działania? Pochodzące z Pythona, można to łatwo osiągnąć za pomocą dekoratora. Udało mi się zrobić coś podobnego dla usług WCF, wprowadzając IOperationBehavior, który nadal nie wydaje się być prosty. Ponieważ pobieranie obiektu według identyfikatora jest czymś, co często musisz zrobić, spodziewam się, że istnieje inny sposób niż kopiowanie kodu.

Idealnie byłoby to wyglądać mniej więcej tak:

[EntityLookup(id => db.Entities.Find(id))] 
public ActionResult Edit(Entity entity) 
{ 
    return View(entity); 
} 

gdzie EntityLookup wykonuje dowolną funkcję mapowania string id do Entity i albo zwraca HttpNotFound lub wywołuje działania z pobranym podmiotu jako parametr.

+0

Czy rozważałeś o wyrażeniach lambda w LINQ ?, co można to, że możesz mieć oddzielną warstwę dostępu do danych, w której możesz pisać funkcje pobierania danych i wywoływać je w ramach metod działania (rozdzielanie problemów). :), Jeśli zamierzasz wykonywać prywatne metody dla każdego pobierania, w kontrolerach będzie wiele linii kodów. –

+0

1. Nadal możesz umieścić swoją walidację bezpośrednio w 'GetEntityById'. 2. Prawdopodobnie szukasz niestandardowego spoiwa do modelu. –

Odpowiedz

3

można napisać niestandardowy ActionFilter:

public class EntityLookupAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     // retrieve the id parameter from the RouteData 
     var id = filterContext.HttpContext.Request.RequestContext.RouteData.Values["id"] as string; 
     if (id == null) 
     { 
      // There was no id present in the request, no need to execute the action 
      filterContext.Result = new HttpNotFoundResult(); 
     } 

     // we've got an id, let's query the database: 
     var entity = db.Entities.Find(id); 
     if (entity == null) 
     { 
      // The entity with the specified id was not found in the database 
      filterContext.Result = new HttpNotFoundResult(); 
     } 

     // We found the entity => we could associate it to the action parameter 

     // let's first get the name of the action parameter whose type matches 
     // the entity type we've just found. There should be one and exactly 
     // one action argument that matches this query, otherwise you have a 
     // problem with your action signature and we'd better fail quickly here 
     string paramName = filterContext 
      .ActionDescriptor 
      .GetParameters() 
      .Single(x => x.ParameterType == entity.GetType()) 
      .ParameterName; 

     // and now let's set its value to the entity 
     filterContext.ActionParameters[paramName] = entity; 
    } 
} 

a następnie:

[EntityLookup] 
public ActionResult Edit(Entity entity) 
{ 
    // if we got that far the entity was found 
    return View(entity); 
} 
+0

Podoba mi się to podejście :) Jednakże, Entity Framwork wydaje obiekt "System.Data.Entity.DynamicProxies. *", Więc porównanie 'entity.GetType()' nie działa zgodnie z zamierzeniami. – mensi

+0

'entity.GetType()." BaseType' działa – mensi

0

Jeśli powtórzenie podobnego kodu można użyć metodę rozszerzenia.

public static class ControllerExtensions 
{ 
    public static ActionResult StandardEdit<TEntity>(
     this Controller controller, 
     DbContext db, 
     long id) 
     where TEntity : class 
    { 
     TEntity entity = db.Set<TEntity>().Find(id); 
     if (entity == null) 
     { 
      return controller.HttpNotFound(); 
     } 
     return controller.View(entity); 
    } 
} 

public ActionResult Edit(long id = 0) 
{ 
    return this.StandardEdit<Client>(db, id); 
} 

Jeśli naprawdę powtarzając dokładnie tego samego kodu, wiele razy to powinno być rozwiązane z dziedziczenia.

Tworzenie wspólnej Controller, która dziedziczy Controller

public class StandardController : Controller 
{ 
    public ActionResult Edit<TEntity>(long id = 0) 
     where TEntity : class 
    { 
     TEntity entity = db.Set<TEntity>().Find(id); 
     if (entity == null) 
     { 
      return HttpNotFound(); 
     } 
     return View(entity); 
    } 
} 

i zmienić swoje kontrolery modelu dziedziczyć z nowego kontrolera:

public class ClientController : StandardController 
{ 
    public ActionResult Edit(long id = 0) 
    { 
     return base.Edit<Client>(id); 
    } 
} 
Powiązane problemy