2

I am creating my first MVC5 / EF / LINQ application and I would like to display the results of several (about 75) "Select Count(*)" queries in one view. The purpose is to display different statistics from a single table on a home page "dashboard", along with a list of "active" items from the same table in the database.

I have read different opinions on how the best way run select county queries in LINQ... What is the most efficient way to do this considering how many queries I need to run on the page?

A sample query would be

select count(*) from TableName WHERE LType="A" AND (LDate BETWEEN 02/10/2015 AND 02/25/2015)

public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
    {
        ViewBag.CurrentSort = sortOrder;
        ViewBag.LastNameSortParam = String.IsNullOrEmpty(sortOrder) ? "LastName" : "";
        ViewBag.DateSortParam = sortOrder == "Date" ? "LeadDate" : "Date";
        if (searchString != null)
        {
            page = 1;
        }
        else
        {
            searchString = currentFilter;
        }

        ViewBag.CurrentFilter = searchString;

        var newLeads = from l in db.WebLeads
                       where (l.LoanAgent == null || l.LoanAgent == "hb@mwfinc.com")
                       select l;                           
        if (!String.IsNullOrEmpty(searchString))
        {
            newLeads = newLeads.Where(l => l.LastName.Contains(searchString)
                                   || l.FirstName.Contains(searchString));
        }
        switch (sortOrder)
        {
            case "Date":
                newLeads = newLeads.OrderBy(l => l.LeadDate);
                break;
            case "LeadDate":
                newLeads = newLeads.OrderByDescending(l => l.LeadDate);
                break;
            case "LastName":
                newLeads = newLeads.OrderBy(l => l.LastName);
                break;
            default:
                newLeads = newLeads.OrderByDescending(l => l.LeadDate);
                break;
        }

        int pageSize = 15;
        int pageNumber = (page ?? 1);

        DateTime minDate = System.DateTime.Today;
        DateTime maxDate = System.DateTime.Now;

        // Leads to Be Assigned Daily Count
        var ctPurchTBA = db.WebLeads.Count(x => (x.LoanType == "Home Purchase" || x.LoanType == "CalPATH Home Purchase")
                              && x.LeadDate >= minDate
                              && x.LeadDate <= maxDate);


        return View(newLeads.ToPagedList(pageNumber, pageSize));                        
    }

'

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
Daniela
  • 657
  • 1
  • 10
  • 25
  • Depending on load/size of tables/overall performance considerations I would go with two approaches: 1. Have one select with sub-selects with the select count(*) as sub-selects. You would need to pass only one item to the vew 2. Load the totals with asyncronous requests from the frontend based with different schedules on table load/volume to reduce sql load. – Stephen Reindl Feb 21 '15 at 00:38
  • Could you provide a sample of approach 1? I am a bit of a newbie, unfortunately, so your answer went a bit over my head. – Daniela Feb 21 '15 at 00:46
  • Since you are using EF/Linq, why dont you use your POCO instead of pure sql. Something like var myPoco = YourDBContext.models And then you can work with mypoco and query it as you prefer – IndieTech Solutions Feb 21 '15 at 00:51
  • example: `select tab1.numbers1, tab2.numbers2, tab3.numbers3 from (select count(*) as numbers1 from Table1) as tab1, (select count(*) as numbers2 from Table2) as tab2, (select count(*) as numbers3 from Table3) as tab3` but be aware that this is a **performance overfill** for an SQL server to handle especially if you talk about 75 tables. Personally I would go with an async process but this is my personal view. – Stephen Reindl Feb 23 '15 at 09:51

1 Answers1

1

As mentioned by Osadella in the comments, you can use the POCO generated by Entity Framework to do this in a much more sane way.

You can do this in SQL, as you're already aware. The problem with using count in SQL is that it is not very performant. You're not gonna notice any huge difference with a dataset like the one you've mentioned, but it's worth knowing that large enterprise applications suffer when using SQL count.

To answer your question however, you should probably use LINQ on the POCO (big data model generated by your DbContext in EF) for the simple reason that you can use it. LINQ is a much simpler abstraction over SQL, there are some fairly good examples here about the benefits of LINQ.

You can use SQL based LINQ or you can use method based LINQ, I'd use method based because it's a lot more readable and easier to write.

The code above;

select count(*) 
from TableName 
WHERE LType="A" 
AND (LDate BETWEEN 02/10/2015 AND 02/25/2015)

would become:

var count = db.TableNames.Count(x => x.LType == "A" 
                                  && x.LDate >= minDate 
                                  && x.LDate <= maxDate);

Obviously you'd need to define minDate and maxDate somewhere as well.

Inspector Squirrel
  • 2,548
  • 2
  • 27
  • 38
  • Thank you very much for the information. This may be out of the scope of the question, but how do I return the results of that query to my view? I have the query set up in my controller. The controller also returns a paginated list of records from the same table that I am querying for the count. See below. Am I setting this up correctly, should the count queries be in the controller? I added the code in the controller to my original post... If I could get an example of how to pass this to the view, I think everything would fall into place for me. Thank you in advance! – Daniela Feb 25 '15 at 21:12
  • How much do you know about View models? – Inspector Squirrel Feb 25 '15 at 21:35
  • I am new to MVC from Web Forms. This is my first application. I have 2 books, but I keep getting hung up on passing multiple models to the view. I have created a database first model for my existing database. Everything thing that I want to do in my above example is from 1 table, so wouldn't I be using just 1 model? – Daniela Feb 25 '15 at 21:50
  • You would be using 1 model yeah, but you'd be using a View model which contains both your domain models. – Inspector Squirrel Feb 25 '15 at 21:53
  • 1
    [Check out this MVC5 Fundamentals tutorial by Pluralsight](http://www.pluralsight.com/training/player?author=scott-allen&name=aspdotnet-mvc5-fundamentals-m1-introduction&mode=live&clip=0&course=aspdotnet-mvc5-fundamentals) – Inspector Squirrel Feb 25 '15 at 21:53
  • 1
    Two of my recent answers regarding the use of View models: [first](http://stackoverflow.com/a/28701771/3846058) and [second](http://stackoverflow.com/questions/28696183/how-to-set-and-get-id-of-buttons-created-within-a-loop/28696785#28696785) – Inspector Squirrel Feb 25 '15 at 21:55
  • If you need any more help, [you can join me in chat](http://chat.stackoverflow.com/rooms/71720/discussion-between-sippy-and-daniela). – Inspector Squirrel Feb 25 '15 at 21:59