0

I clearly don't know what I'm doing. This MVC stuff is really blowing my mind in trying to keep with the pattern. I've been following the MVC tutorials as well as mega-googling and this is the corner I've painted myself into.

I have multiple similar pieces of data I'm trying to get to a view. I'm able to get my code to work, but to me it just looks like it's going to be highly inefficient as we start pulling large recordsets from the db due to multiple calls to the db. So, I have a OrderSummary class, inside the class is this:

public IEnumerable<Order> GetOrders()
{
   var orders = (from s in db.Orders
                 where s.UserId == uId
                 select s);

   return orders.ToList();
}

Then this:

public decimal GetGrossProfitTotal()
{
   var orders = (from s in db.Orders
                 where s.UserId == uId
                 select s);
   decimal? grossprofittotal = orders.Sum(s => s.Profit);

   return grossprofittotal ?? decimal.Zero;
}

So, if we take that last chunk of code and copy it for totalcommission and netprofittotal that's basically how I have things layed out. I would guess four calls to the db?

Then in the controller:

        var ordersummary = new OrdersSummary();
        var viewModel = new OrderSummary
        {
            Orders = ordersummary.GetOrders(),
            GrossProfitTotal = ordersummary.GetGrossProfitTotal(),
            CommissionTotal = ordersummary.GetCommissionTotal(),
            NetProfitTotal = ordersummary.GetNetProfitTotal(),
        };
        return View(viewModel);

This gets me all the data I need in the view so I can work with it. To me, it just seems unnecessarily redundant and I'm guessing inefficient? If you throw in that I'm also doing sort and search parms, it's a lot of duplicate linq code as well. It seems like I should be able to do something to consolidate the data like this:

   var orders = (from s in db.Orders
                 where s.UserId == uId
                 select s).ToList();

   decimal grossprofittotal = orders.Sum(s => s.Profit);
   decimal commissiontotal = orders.Sum(s => s.Commission);
   decimal netprofittotal = orders.Sum(s => s.Profit + s.Commission);

and then wrap those four pieces of data (orders list, and three decimal values) up nicely in an array (or whatever) and send them to the controller/view. In the view I need to be able to loop through the orders list. Am I way off here? Or, what is standard procedure here with MVC? Thanks.

tereško
  • 58,060
  • 25
  • 98
  • 150
Sum None
  • 2,164
  • 3
  • 27
  • 32

2 Answers2

1

Yes, fetching the same data four times is indeed inefficient, and completely unneccesary. You can very well fetch it only once and then do the other operations on the data that you have.

You can keep the GetOrders method as it is if you like, but that's all the data that you need to fetch. If you fetch the data in the controller or in the model constructor is mostly a matter of taste. Personally I tend to put more logic in the model than the controller.

As long as you use ToList to make sure that you actually fetch the data (or any other method that realises the result as a collection), you can calculate the sums from what you have in memory. (Without it, you would still be doing four queries to the database.)

Instead of summing up the profit and commision from all items to get the net profit total, you can just calculate it from the other sums:

decimal netprofittotal = grossprofittotal + netprofittotal;
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Thanks, makes perfect sense, and sounds like I need to go back to the fundamentals rather than thinking of MVC as a whole new rigid way to do things. Unfortunately, my fundamentals are spotty, but I can at least look outside of the box now and generally know where to find the answers. I really appreciate the help. – Sum None Jun 26 '13 at 16:00
1

LinqToEntities tranlates all query into SQL. If you don't want to make more than one transaction, you can fetch the result into a variable by .ToList(),querying this object make the calculation by linqToObject in the memory.

Backward: It fetchs all orders from database first.

 var ordersInMemory = orders.ToList();
 decimal grossprofittotal = ordersInMemory.Sum(s => s.Profit);
 decimal commissiontotal = ordersInMemory.Sum(s => s.Commission);
 decimal netprofittotal = grossprofittotal + commissiontotal ;
speti43
  • 2,886
  • 1
  • 20
  • 23
  • The `AsEnumerable` method only returns the reference as an `IEnumerable`, it doesn't force the query, so your code would still do three database calls, not one. http://msdn.microsoft.com/en-us/library/bb335435.aspx – Guffa Jun 26 '13 at 12:11
  • Yes, returns, but in that case the object uses the default implementations of methods, and it's swich to in-process mode. Am I misunderstanding something? http://msmvps.com/blogs/jon_skeet/archive/2011/01/14/reimplementing-linq-to-objects-part-36-asenumerable.aspx – speti43 Jun 26 '13 at 14:39
  • This also prove my predicate: http://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet – speti43 Jun 26 '13 at 14:44
  • That works for a single query when you continue the query in the same statement. The next method will pull the result from the server. In this case the next method would be the `Sum` calls, so each one will pull a new result from the database. – Guffa Jun 26 '13 at 14:50
  • Ok, I made some modification, what about this approach? I'm watching, you suggested the same. ToArray() can work also. – speti43 Jun 26 '13 at 15:03
  • So...let's say I use this exact piece of code in my GetOrders method in my model. How do I call/reference this in my controller? It looks to be four pieces of data and I'm only aware how to return one. – Sum None Jun 30 '13 at 13:39
  • What would you like to send to the view? You mentioned the view need to loop through the orders list. Why would you do that on the view (with javascript?) or you want to pass four values and bind it to four fields of the view? – speti43 Jul 01 '13 at 07:23
  • sorry for late response...still trying to figure out this SO interfce...but I would like to get basically a grid with the totals at the bottom and eventually some chart data... so, for starters, the list/grid is up top, then the totals would be at the base of the list columns corresponding to Total Profit, Total Commission, and Gross Profit. I was trying to use a tuple, but I can't get the syntax right in calling the tuple in the controller. I guess this was more my question the whole time as I knew the multiple db calls was wrong. Thanks. – Sum None Jul 01 '13 at 10:20
  • Also, all my methods,classes and such are in the model construct (view model) instead of the controller. Seems I can probably make it work in the controller if I just dump all the stuff there as that's how it was in one of the tutorials I did, but then the controller is fat. Thanks again. – Sum None Jul 01 '13 at 10:23
  • I don't see any problems with this. Just make an object in your model which contains: ienumerable,decimal,decimal,decimal. Return the view from the controller, and in the view you will see these objects in your model, and you can bind the single fields and foreach through the enumerable and build a "grid" with table rows: http://stackoverflow.com/questions/966698/c-sharp-mvc-optional-columns-in-grid-foreach – speti43 Jul 01 '13 at 10:26
  • To sum up my confusion, I just don't know how to pass the data back and forth between the model, controller and view. It seems if you want to pass a single table from the database, it's magically simple, but if you're trying to pass multiple pieces of data to a view, it becomes infinitely more complex, at least in my opinion. I'm hoping it clicks at some point. Regards. – Sum None Jul 01 '13 at 10:29
  • Hmmm, as far as I can tell, that link is not even close to what I'm trying to do. I'll keep googling for an example hopefully... – Sum None Jul 01 '13 at 11:52
  • I created a new question to try and explain what I'm doing...but keep in mind, I have no idea what I'm doing, so I might be way off base: http://stackoverflow.com/questions/17405505/mvc-passing-four-pieces-of-data-to-the-controller-and-subsequently-to-the-view – Sum None Jul 01 '13 at 13:24