asp.net mvc , raw sql : Display data in Views generated using aggregate function

asp.net-mvc entity-framework-6 sql sql-server

Question

I am using ASP.NET MVC, EF 6 and SQL Server 2008.

I want to generate a view which would show sum of all the sales in each day for a particular month in a particular year.

I found LINQ query very complicated in such type of job, So I used a raw SQL query. I wrote query and tested in SQL server and it worked fine.

select  
    YEAR(Date) as Year, 
    MONTH(Date) as month, 
    DAY(Date) as date,   
    SUM(GrandTotal) as Total  
from 
    Sales 
where 
    Year(Date) = 2014 
    and MONTH(Date) = 12 
group by 
    DAY(Date), YEAR(Date), MONTH(date)

Result

Image showing all the sales in 2014 and result of the query above

Well currently I don't have much data. But it looks like I got what I wanted from a query.

I wrote a controller for this purpose and now I have no idea how to display this data in View.

public ActionResult MonthlySalesByDate()
{
        DateTime today = DateTime.Now.Date;
        int _year = today.Year;
        int _month = today.Month;

        //raw sql query 
        string query = "select SUM(GrandTotal) as Total, DAY(Date) as date, MONTH(Date) as month, YEAR(Date) as Year from Sales where Year(Date) = " + _year + " and MONTH(Date) =" + _month + "  Group by DAY(Date), YEAR(Date), MONTH(date)";

        //executing raw sql query 
        var _model = db.Stocks.SqlQuery(query).ToList();           

        return View(_model);
}

Please help me out with this. If there is better way of doing this or if I am making mistakes, please let me know.

1
3
10/24/2015 7:24:24 AM

Accepted Answer

Start by creating view models to represent what you want to display in the view

public class DayTotalVM
{
  public int Day { get; set; }
  [DisplayFormat(DataFormatString = "{0:C}")]
  public decimal Total { get; set; }
}
public class SalesVM
{
  [DisplayFormat(DataFormatString = "{0:MMMM yyyy}")]
  public DateTime Date { get; set; }
  public List<DayTotalVM> Days { get; set; }
}

The sql query you have can be generated in linq and projected into your view models using

int year = 2014;
int month = 12;
var query = db.Sales.Where(x => x.Date.Year == year && x.Date.Month == month)
    .GroupBy(x => x.Date).Select(g => new DayTotalVM
    {
        Day = g.Key.Day,
        Total = g.Sum(x => x.Total)
    })

However this will only give you the 2 items as per you above image, but from the comments you want to display all days in the month, so you can add

int daysInMonth = DateTime.DaysInMonth(year, month);
List<DayTotalVM> days = new List<DayTotalVM>();
for(int i = 1; i < daysInMonth + 1; i++)
{
    DayTotalVM item = new DayTotalVM () { Day = i };
    DayTotalVM ex = query.Where(x => x.Day == i).FirstOrDefault();
    if (ex != null)
    {
        item.Total = ex.Total;
    }
    days.Add(item);
}

and finally initialize and return your view model

SalesVM model = new SalesVM();
{
  Date = new DateTime(year, month, 1),
  Days = days 
}
return View(model);

And then the view would be

@model SalesVM
@Html.DisplayFor(m => m.Date);
<table>
  @for(int i = 0; i < Model.Days.Count; i++)
  {
    <tr>
      <td>@Html.DisplayFor(m => m.Days[i].Day)</td>
      <td>@Html.DisplayFor(m => m.Days[i].Total)</td>
    </tr>
  }
</table>

Edit

The for loop could be replace by using a GroupJoin()

public ActionResult MonthlySalesByDate(int year, int month)
{
  int daysInMonth = DateTime.DaysInMonth(year, month);
  var days = Enumerable.Range(1, daysInMonth);
  var query = db.Sales.Where(x => x.Date.Year == year && x.Date.Month == month).Select(g => new
  {
    Day = g.Date.Day,
    Total = g.Total
  });
  var model = new SalesVM
  {
    Date = new DateTime(year, month, 1),
    Days = days.GroupJoin(query, d => d, q => q.Day, (d, q) => new DayTotalVM
    {
      Day = d,
      Total = q.Sum(x => x.Total)
    }).ToList()
  };
  return View(model);
}
2
10/24/2015 8:43:33 AM


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