Entity Framework queries and MVC ViewModels

asp.net-mvc c# entity-framework repository-pattern viewmodel

Question

I'm new to MVC and Entity Framework, and I have a question concerning the proper or advised method of doing this.

In terms of how I am creating this application, I have kind of been following the Nerd Dinner MVC application. I have a page with information from many different sources. It features a dropdown list from a lookup table and displays information from many separate tables.

I put all of this data into a class called a ViewModel:

class DetailsViewModel {
    public List<Foo> DropdownListData { get; set; }

    // comes from table 1
    public string Property1 { get; set; } 
    public string Property2 { get; set; }

    public Bar SomeBarObject { get; set; } // comes from table 2
}

Their examples in the Nerd Dinner code are a touch too straightforward. There is just one object that the DinnerFormViewModel accepts: Dinner. A SelectList for the nations depending on the location of the meal is created based on the dinner.

Their data access code is likewise rather straightforward due to the simplicity. He has a straightforward DinnerRepository with a GetDinner function (). He can do simple actions like:

Dinner dinner = new Dinner();

// return the view model
return View(new DinnerFormViewModel(dinner));

OR

Dinner dinner = repository.GetDinner(id);

return View(new DinnerFormViewModel(dinner));

Creating an anonymous type: My query is far more complicated than this and pulls data from various tables.

var query = from a in ctx.Table1
            where a.Id == id
            select new { a.Property1, a.Property2, a.Foo, a.Bar };

I'd want to know the following:

What structure should my repository class have? Should the repository class provide back the actual ViewModel? Given that the ViewModel seems to imply that it is being utilized in a view, that doesn't seem like the appropriate course of action. How can I get an anonymous object from my repository so that I may build the ViewModel in my controller actions as my query returns an anonymous object?

1
19
6/29/2012 5:40:38 AM

Accepted Answer

Your point that a repository shouldn't return a view model is valid. Because changing your display will need changing your data layer.

You should have a collective root repository. I would extract a new class to handle this if your property1, property2, Foo, and Bar are connected in any manner.

public class FooBarDetails
{
   public string Property1 {get;set;}
   public string Property2 {get;set;}
   public Foo Foo {get;set;}
   public Bar Bar {get;set;}
}

var details = _repo.GetDetails(detailId);

It could be possible to offer a service to construct your FooBarDetails if Foo and Bar have no connection to one another at all.

FooBarDetails details = _service.GetFooBar(id);

where GetFooBar(int) would seem similar to this:

_fooRepo.Get(id);
_barRepo.Get(id);

return new FooBarDetails{Foo = foo, Bar = bar, Property1 = "something", Property2 = "something else"};

All of this is speculative since your domain will greatly influence how the repository is designed. It is challenging to create possible linkages between your things when you use general phrases.

Updated If we are working with an Order's aggregate root, it is clear from the remark. The OrderItem and the client who made the order are both included in an order.

public class Order
{
    public List<OrderItem> Items{get; private set;}
    public Customer OrderedBy {get; private set;}
    //Other stuff
}

public class Customer
{
  public List<Orders> Orders{get;set;}
}

An order object from your repo should be properly hydrated.

var order = _rep.Get(orderId);

I would transmit the order straight to the view model since your order has all the necessary information.

public class OrderDetailsViewModel
{
  public Order Order {get;set;}
  public OrderDetailsViewModel(Order order)
  {
    Order = order;
  }
}

Now it can appear excessive to have a viewmodel with only one object (and it most likely will be at first). It begins to assist if you need to show more objects on your view.

public class OrderDetailsViewModel
{
  public Order Order {get;set;}
  public List<Order> SimilarOrders {get;set;}
  public OrderDetailsViewModel(Order order, List<Order> similarOrders)
  {
    Order = order;
    SimilarOrders = similarOrders;
  }
}
8
5/23/2017 12:14:20 PM

Popular Answer

While the most of the responses are accurate, I believe that you left out a crucial component of your question that appears between the lines.

First of all, there isn't a 100 percent correct approach, so I wouldn't worry too much about the specifics of the pattern to employ just now. You will begin to see what is working and what isn't as your application develops, and you will learn how to adjust it to work best for you and your application. My Asp.Net MVC backend's design has just been entirely altered, mostly due to the fact that a lot of the advise I received didn't apply to what I was attempting to do.

In light of this, consider your layers in terms of what they are meant to do. The repository layer's main purpose is to add, remove, edit, and modify data in your data source. It has no idea how the data will be utilized and, to be quite honest, doesn't care. Repositories need to hence just return your EF entities.

You need a layer between your controllers and the repositories, which is often referred to as the service layer or business layer. This is the portion of your query that others seem to be missing. The classes in this layer may be organized anyway you choose; controllers call these classes. Each of these classes will make a request to the repository to get the needed data, then transform it into the view models your controllers will ultimately use.

Your business logic is placed in this service/business layer; if you stop to think about it, transforming an object into a view model is also business logic since it specifies how your application will actually utilize that data. This implies that you are not required to use any particular conversion techniques. The notion is that your controllers are unaware of the actual database structure or the methods used to access the data; instead, they are given business entities (view models) after giving your service/business layer instructions on what to do.

The only layer that calls repository classes should be the service layer.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow