D.M
D.M

Reputation: 429

Showing First Instance and Last Instance of GroupBy ASP.NET MVC

I have a dashboard that shows an updated list of application errors. Some errors have happened more than once so I have grouped them by their error type and placed a count on them to see how many times this error has occurred. I am wanting to find out when the first date the error occurred, which is fairly straight forward, but also the last date it occurred too to see how long this error has been persisting.

Below I show both my current output and expected output

Current Output

enter image description here

Expected Output

enter image description here

Below I show my code. What changes would I need to make in order to display the last date as well as the first date? I have tried using LastOrDefault() but this doesn't actually work as when the LINQ query is converted into a SQL statement, there is no BOTTOM 1 command.

Controller

public ActionResult Errors(string sortOrder, int? page)
{
        ViewBag.CurrentSort = sortOrder;
        ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";


        var queryString = RouteData.Values["id"];

        var applications = db.ElmahErrors.Where(s => s.Application.Replace("/", "").Replace(".", "") == queryString)
                    .GroupBy(s => s.Type)
                    .Select(grp => new ErrorCountModel
                    {
                        ErrorCount = grp.Count(),
                        ElmahError = grp.FirstOrDefault()
                    });

        switch (sortOrder)
        {
            default:
                applications = applications.OrderBy(s => s.ElmahError.TimeUtc);

                break;
        }


        int pageSize = Int32.Parse(System.Configuration.ConfigurationManager.AppSettings["DefaultPageSize"]);
        int pageNumber = (page ?? 1);

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

ErrorCount Model

public class ErrorCountModel
{
        public int ErrorCount { get; set; }
        public ElmahError ElmahError { get; set; }
}

Any help on this matter would be greatly appreciated.

Thanks in advance.

Upvotes: 2

Views: 81

Answers (2)

rism
rism

Reputation: 12132

Another way to do this would have been to create a view model as follows:

public class ElmahErrorViewModel {
   public Guid ID {get;set;}
   public string Application {get;set;}
   public string Host {get;set;}
   public string Type {get;set;}
   public int ErrorCount {get;set;}
   public DateTime Min {get;set;}
   public DateTime Max {get;set;}
}

And then just:

var applications = db.ElmahErrors.Where(s => s.Application.Replace("/", "").Replace(".", "") == queryString)
     .GroupBy(s => new { s.Type, s.ID, s.Application, s.Host })
     .Select(grp => new ElmahErrorViewModel {
           ID = grp.Key.ID,
           Application = grp.Key.Application,
           Host = grp.Key.Host,
           Type = grp.Key.Type,
           ErrorCount = grp.Count(),
           Min = grp.Min(m => m.TimeUtc),
           Max = grp.Max(m => m.TimeUtc),
     });

The idea being that this returns a flattened model ready to go whereas I assume with a LastElmahError property you still have to flatten it at some point to display it in the UI and the only field you actually want out of that is TimeUtc so most of it is redundant.

Upvotes: 0

Rob
Rob

Reputation: 27357

Side note: The following is not guaranteed to give you the newest error, because you haven't told it to sort

ElmahError = grp.FirstOrDefault()

It should be this:

ElmahError = grp.OrderBy(s => s.ElmahError.TimeUtc).FirstOrDefault();

I would have expected .LastOrDefault() to work, but if it really doesn't, you can do this:

LastElmahError = grp.OrderByDescending(s => s.ElmahError.TimeUtc).FirstOrDefault();

Essentially, you reverse the ordering of the first error.

Also, add this to your ErrorCountModel model class:

public ElmahError LastElmahError { get; set; }

Upvotes: 0

Related Questions