2012-04-03 4 views
1

Ich habe gerade angefangen, View & Domain-Modell-Design in meiner MVC-Web-App, aber habe die Frage, wo Berechnungen und andere View-bezogene Aktionen durchführen. Ich werde versuchen, ein Beispiel zu geben.Ansicht und Domain-Modell, wo die Berechnung durchgeführt wird

My Domain Model (Linq2Sql)

public class Product 
{ 
    public int Id; 
    public string Name; 
} 

The View Modell mit neuer UserCount Eigenschaft, die Ich mag würde berechnen.

public class ProductViewModel 
{ 
    public int Id; 
    public string Name; 
    public int UserCount; 
} 

Mein Controller-Aktion sieht aus wie

public ActionResult _SelectionClientSide_Products() 
{ 
    IQueryable<Product> products = _repository.GetProducts(true); 
    var model = Mapper.Map<IEnumerable<Product>, IEnumerable<ProductViewModel>>(products);         
    return View(model); 
} 

ich nach Daten abfragen Repository-Methode und bekommen IQueryable<Product> und wo es zu ProductViewModel Liste. Aber ich muss auch einen anderen Abfragevorgang durchführen, um Benutzer für jedes abgefragte Produkt zu zählen und alle Werte ProductViewModel zuzuordnen. Welchen Entwurf sollte ich befolgen, um dies zu erreichen?

Die Beziehung zwischen Tabellen

Products -> Orders - > Users 

EDIT

ich mich entschlossen habe AutoMapper zu entfernen, weil es mehr Probleme als Vorteile gibt und meine eigene Builder, die alles enthalten, was ich brauche. Ich mache Feld zuweisen und auch Berechnung hinzufügen.

public ActionResult _SelectionClientSide_Products() 
    {   
     Data = new ProductViewModelBuilder(_repository).Build(); 
     return View(Data); 
    } 

namespace PC.Models 
{ 
      public class ProductViewModel 
      { 
       public int Id { get; set; } 
       public string Name { get; set; } 
       public int UsersCount { get; set; } 
      } 

      public class ProductViewModelBuilder 
      { 
       private readonly IDataAccess _repository; 

       public ProductViewModelBuilder(IDataAccess repository) 
       { 
        _repository = repository; 
       } 

       public IQueryable<ProductViewModel> Build() 
       { 
        return _repository.GetProducts().Select(p=> new ProductViewModel 
                     { 
                      Id = p.Id, 
                      Name = p.Name, 
                      UsersCount = _repository.CountUsers(p.Id) 
                     });   
       } 

      } 
     } 

Antwort

0

Meiner Meinung nach, von der Zeit der Controller Modell-Setup ist es begonnen hat, soll es auf das Modell nicht mehr „Logik“ oder im Gespräch sein. Einen Builder zu haben, der das Modell erneut abfragt, ist eine schlechte Übung. Nicht wirklich "brechen" das MVC-Muster, aber immer noch schlechte Praxis. Ihr ViewModel ist von Ihrer DAL abhängig. Schlechter böser Junge. :)

Wenn Sie eine andere Abfrage ausführen müssen, sollte das in der ursprünglichen Abfrage eingekapselt werden. Anstatt _repository.GetProducts aufzurufen, rufen Sie eine andere Methode auf, die nicht nur die Produkte erhält, sondern auch die Anzahl. Erstellen Sie bei Bedarf ein DTO.

Dann sollten Sie Ihre Controller wie folgt aussehen:

public ActionResult _SelectionClientSide_Products() 
{ 
    var someDto = _repository.GetProductsAndUserCount(true); 
    var model = Mapper.Map<IEnumerable<SomeDto>, IEnumerable<ProductViewModel>>(someDto);         
    return View(model); 
} 

ich persönlich für generische Repositories über spezialisiertere gehen, wie ich mit 50 Unterschriften keine IProductRepository Schnittstelle wollen. Ich entscheide mich für LINQ IEnumerable<T> Erweiterungen (aka "Pipes und Filter"), die komplexe Abfragen ermöglicht und in meiner Domäne bleiben.

So ist meine Version des obigen wäre:

public ActionResult _SelectionClientSide_Products() 
{ 
    var someDto = _productRepository.Find().WithSomeCondition(true).ToSomeDto(); 
    var model = Mapper.Map<IEnumerable<SomeDto>, IEnumerable<ProductViewModel>>(someDto);         
    return View(model); 
} 

Auf einer seitlichen Anmerkung, warum sagen Sie AutoMapper verursacht Sie Probleme mehr Vorteile, die? AutoMapper hat mir Tonnen von repetitivem Code gespart. Wenn Sie wissen, wie man es richtig benutzt, ist es Ihr bester Freund. Übergibt das wichtigste NuGet-Paket in meiner aktuellen Anwendung.

+0

Ich habe gelesen, dass es schlechte Praxis ist, zusätzliche Felder im Domänenmodell zu erstellen, wenn diese Felder nur einmal in einem View-Modell benötigt werden. Wenn Ihre Beispielrepository _repository.GetProductsAndUserCount-Methode das Domänenmodell zurückgibt (nicht sicher, aber so scheint es), ist das Feld UserCount jedoch standardmäßig nicht vorhanden.Also schlagen Sie vor, Calculate Field im Domain Model zu erstellen (ich benutze linq2sql und würde diese Case Domain partielle Klasse erweitern)? Aber wie gesagt, ich habe gelesen, dass das nicht praktikabel ist. – Tomas

+0

@Tomas - es ist ein DTO. Zweck ist also, ein oder mehrere Domänenobjekte zu umbrechen, damit sie im App-Stapel übertragen werden können. Wie ist diese schlechte Praxis? Ihr ProductViewModelBuilder ist eine schlechte Vorgehensweise. – RPM1984

+0

Ich benutze Linq2SQL und mein DTO ist automatisch generierte Klassen von Linq2Sql Builder. Die Produkt (DTO) -Klasse hat keine UserCount-Eigenschaft, ich kann sie mit der Partial-Klasse erweitern, aber sie ist nicht rational, weil die gleiche Produktklasse an anderer Stelle verwendet wird. Also sollte ich eine andere DTO-Klasse ähnlich Product DTO von Linq2Sql generiert erstellen und UserCount-Eigenschaft hinzufügen und dann var someDto = _productRepository.Find(). WithSomeCondition (true) .ToSomeDto(); – Tomas