Linq Entity Framework grouping and joins on names, year and month - c#

I am developing an ASP.NET MVC Appliction with MYSQL and Entity Framework. I have customers making payments made to some payment categories. I want to develop a ledger where I have customer names and all the classes of payments with total payments made for any particular pay category by each customer. And I will have to group by name, year and month. And be able to filter by year, month or customerid. I have 25 payment categories.
The solution I have made is ancient- it makes use of 25 joins to the get the categories, sum the payments and assign these to a viewmodel. This runs on my developing machine alright but it fails on my server with the error
MySql.Data.MySqlClient.MySqlException: Too high level of nesting for select
Can anyone give me a better approach to achieving this goal
My Code is like below
public ActionResult LedgerReport(int? year, int? month, int? CuId)
{
var query = LedgerYrMn(year, month, CuId);
return View(query);
}
public IEnumerable LedgerYrMn(int? year, int? month, int? CuId)
{
DateTime lastmonth = DateTime.Now;
DateTime thismonth = DateTime.Now;
DateTime thismonthstart = DateTime.Now;
if (year.HasValue && month.HasValue)
{
lastmonth = (new DateTime(year.Value, month.Value, DateTime.DaysInMonth(year.Value, month.Value)).AddMonths(-1));
thismonth = (new DateTime(year.Value, month.Value, DateTime.DaysInMonth(year.Value, month.Value)));
thismonthstart = (new DateTime(year.Value, month.Value, 1));
}
var query =
(
from bk in db.Customers
// pay category 1
join tr in db.Payments
.Where(a => a.PDate <= thismonth && a.PDate >= thismonthstart && a.paycategory.Id == 1 && a.Paid=true)
on bk.CustomerID equals tr.CustomerID into trs
// pay category 2
join tr2 in db.Payments
.Where(a => a.PDate <= thismonth && a.PDate >= thismonthstart && a.paycategory.Id == 2 && a.Paid=true)
on bk.CustomerID equals tr2.CustomerID into trs2
......
etc to the 25 payment categories.
}
select new LedgerViewModel
{
food=(int?)trs.Sum(c => c.Pay) ?? 0,
fuel=(int?)trs.Sum(c => c.Pay) ?? 0
.. etc
});
return query.AsEnumerable();
}

Related

Linq searches for recent birthdays (within 15 days)

How to use Linq
A table
Field Birthday
Linq searches for recent birthdays (within 15 days)
from a in Employee where a.PositionStatus == true select new{ a.Name,a.Birthday}
Try below query
var fromdate = DateTime.Now;
var todate = DateTime.Now.AddDays(15);
var result =
(
from a in Employee
where a.PositionStuats==true && a.DateOfBirth.Value.Month >= fromdate.Month &&
a.DateOfBirth.Value.Month <= todate.Month &&
a.DateOfBirth.Value.Day >= fromdate.Day && a.DateOfBirth.Value.Day <= todate.Day
select new{ a.Name,a.Birthday}
).ToList();
Depending on your entity frame work version you can also replace a.DateOfBirth.Value.Month with a.DateOfBirth.Month.

how can i wirte linq to compair the year and month f

I am trying to fetch record from my database year and month vise
I have write following linq
Connection cn = new Connection();
IMongoDatabase db = cn.ConnectionString();
var collection = db.GetCollection<HolidayListModel>("Holiday");
var filter = Builders<HolidayListModel>.Filter.Eq("business_id", businessid);
try
{
var obj = collection.Find(filter).ToListAsync();
if (obj != null && obj.Result != null)
{
if (month == "All")
{
holidaylist = obj.Result.Where(x => DateTime.Parse(x.date).Year == selectedyear).OrderBy(x => DateTime.Parse(x.date)).Select(x => new HolidayListModel()
{
_id = x._id,
business_id = x.business_id,
festival = x.festival,
date = x.date,
day = x.day
}).ToList();
}
else
{
holidaylist = (from x in obj.Result where (( x.date == month )) select x).ToList();
}
Here with lambda expression I got the data year vise using query expression I can't find a way to fetch data using year and month
Can someone guide me how can I write linq for this problem
This is usually done simply by using a start/end value; so foo.Year == selectedYear or foo.date == month becomes simply foo >= #start && foo < #end (the end is usually exclusive, so for a "year" check, that would be 1 Jan of the next year; for a "month" check it would be the 1st of the next month; this means that times in the last day are still always treated correctly).
If you are storing your dates in mongodb as strings that are ISO 8601 or similar, you could also do the same thing simply with string comparisons, without any "parse" logic.

linq to retrieve name instead of id and list in descending order

can u help me to solve this.
i'm retrieving the balance of each heads, and i retrieved the balance of each heads. Now i want to list the balance in the descending order and list the name instead of h_id. i used the code
protected void account_watchlist() {
using(var context = new sem_dbEntities()) {
//ledger && head
var year = DateTime.Now.AddMinutes(318).Year;
var month = DateTime.Now.AddMinutes(318).Month;
var start = new DateTime();
if (month >= 4) {
start = new DateTime(year, 04, 01);
} else if (month < 4) {
start = new DateTime(year - 1, 04, 01);
}
var qr = (from a in context.ledgers
where a.entry_date >= start && a.entry_date < new DateTime(year, month, 1)
join b in context.heads on a.h_id equals b.h_id
group a by a.h_id into sb select new {
sb.FirstOrDefault().h_id,
totalc = sb.Sum(c => c.credit),
totald = sb.Sum(d => d.debit),
balance = sb.Sum(d => d.debit) - sb.Sum(c => c.credit)
}).ToList();
Repeater2.DataSource = qr.ToList();
Repeater2.DataBind();
}
}
You need to use group join of heads with ledgers. It will give you access both to head entity and all related ledgers (in headLedgers collection):
from h in context.heads
join l in context.ledgers.Where(x => x.entry_date >= startDate && x.entry_date < endDate)
on h.h_id equals l.h_id into headLedgers
where headLedgers.Any()
let totalc = headLedgers.Sum(l => l.credit),
let totald = headLedgers.Sum(l => l.debit),
select new {
h.h_id,
h.name,
totalc,
totald,
balance = totald - totalc,
}
I also introduced two range variables for total credit and total debit (consider better names here) to avoid calculating them second time for balance.

Fetch data by upcoming birthdays in linq to sql

I want to show list of people whose birthdays are in coming 15 days. I have below dates in my table column:
LET ME MORE CLEAR MY QUESTION
BELOW IS MY EMPLOYEE TABLE COLUMNS
EMP_ID |EMP_TYPE |EMP_USERNAME |EMP_DOB
======= |========== |=============== |==================
1 |ADMIN |ELENA GILBERT |1993-02-19
2 |EMPLOYEE |KATHERINE PIERCE |1993-03-19
3 |EMPLOYEE |STEFAN SALVATORE |1993-04-19
4 |EMPLOYEE |DAMON SALVATORE |1993-05-19
5 |EMPLOYEE |JEREMY GILBERT |1993-05-20
Now I just want to show upcoming birthdays in 15 days.
Below I created a custom class in which I set two properties:
public class Birthday
{
public string Name { get; set; }
public DateTime date { get; set; }
}
Below is my web method which return me a list from which I want just Emp_Username and Emp_DOB which upcoming within 15 days.
[WebMethod]
public static List<Birthday> getBirthday()
{
var slist = new List<Birthday>();
var db = new BLUEPUMPKINEntities();
var query = (from emp in db.Employees
let BirthdayDiff = (new DateTime(DateTime.Now.Year,
emp.EMP_DOB.Value.Month, emp.EMP_DOB.Value.Day) - DateTime.Now).TotalDays where BirthdayDiff >= 0 && BirthdayDiff <= 15
select new Birthday { Name = emp.EMP_USERNAME, date = Convert.ToDateTime(emp.EMP_DOB) });
return slist.ToList();
}
Problem is my above code is not working and not showing any errors in de-bugging.
You should change your query to something like this and then return it:
[WebMethod]
public static List<Employee> getBirthday()
{
var db = new BLUEPUMPKINEntities();
const int dateOffset = 15;
var today = DateTime.Today;
var maxDate = DateTime.Today.AddDays(dateOffset);
return (from emp in db.Employees
where emp.EMP_DOB.Value >= today
where emp.EMP_DOB.Value <= maxDate
select emp).ToList();
}
There are at least three issues in your code.
Firstly, this line can potentially produce incorrect results:
let BirthdayDiff = (new DateTime(DateTime.Now.Year, emp.EMP_DOB.Value.Month, emp.EMP_DOB.Value.Day) - DateTime.Now).TotalDays
Note that you use the current time to produce year
DateTime.Now.Year
And consider the following case:
Now is 25-Dec-15 and One of your Employee is having birthday in
3-Jan-16. According to the calculation, you would produce DateTime
with value of 3-Jan-15 for your Employee and you minus it with
DateTime.Now and thus you will get value < -300 in total days.
Secondly, don't use DateTime.Now more than once in a single query, because the result of the subsequent DateTime.Now may be different from the first one. Use only once:
DateTime now = DateTime.Now; //and then just use now
Or even better, to remove all hours and minutes discrepancy:
DateTime today = DateTime.Today;
And lastly, you never return the result of the query, but only an empty List.
Note that you define:
var slist = new List<Employee>();
And the query:
var db = new BLUEPUMPKINEntities();
var query = from emp in db.Employees
let BirthdayDiff = (new DateTime(DateTime.Now.Year, emp.EMP_DOB.Value.Month, emp.EMP_DOB.Value.Day) - DateTime.Now).TotalDays
where BirthdayDiff >= 0 && BirthdayDiff <= 15
select emp;
But you neither relate your slist with query nor return the query itself. Thus, you always get nothing, because slist is always an empty, new List.
Minor Edit: change from db to db.Employees and adding ToList()
Correct three of them and you have a safe way to do get what you want (Note: beware of leap year):
[WebMethod]
public static List<Employee> getBirthday()
{
var slist = new List<Employee>();
var db = new BLUEPUMPKINEntities();
var today = DateTime.Today; //2.
return (from emp in db.Employees
let BirthdayDiff = (new DateTime(today.Year, emp.EMP_DOB.Value.Month, emp.EMP_DOB.Value.Day) - today).TotalDays
let TrueBirthdayDiff = BirthdayDiff >= 0 ? BirthdayDiff : BirthdayDiff + 365 + Convert.ToInt32(DateTime.IsLeapYear(now.Year)) //1, 3 and leap year
where TrueBirthdayDiff >= 0 && TrueBirthdayDiff <= 15
select emp).ToList();
}
By using below query I found a way to know upcoming birthdays. I don't know why folks down voted my this post.
var day = DateTime.Now.Day;
var month = DateTime.Now.Month;
var query = (from emp in db.Employees
where emp.EMP_DOB.HasValue == true
&& emp.EMP_DOB.Value.Day >= day && emp.EMP_DOB.Value.Month == month
select new Birthday
{
Name = emp.EMP_USERNAME,
date = emp.EMP_DOB.Value
}).ToList();
return query;
You're returning an empty list...
[WebMethod]
public static IList<Employee> getBirthday() //<-- changed signature to IList
{
var slist = new List<Employee>();
var db = new BLUEPUMPKINEntities();
var query = from emp in db.Employees
let BirthdayDiff = (new DateTime(DateTime.Now.Year,
emp.EMP_DOB.Value.Month, emp.EMP_DOB.Value.Day) - DateTime.Now).TotalDays
where BirthdayDiff >= 0 && BirthdayDiff <= 15
select emp;
//return slist; //<-- problem right here!
return query.ToList(); //<-- this should fix it...!
}
If your heart and soul is really tied to that List<T>, then do this right before the return slist:
slist.AddRange(query);
HTH!

How to convert nested sql statement to linq to entities?

I'm trying to create a basic room availability statement to use with linq to entity framework. I have two tables: 'Room' including columns RoomID/RoomSize and 'Booking' including BookingID/RoomID/StartDate/Enddate.
I have got a working sql statement:
SELECT RoomID, RoomSize from Room
where RoomID NOT IN (SELECT RoomID from booking
where ('08/01/2015' >= [start] AND '08/01/2015' <= [end]) OR ('08/20/2015' >= [start] AND '08/20/2015' <= [end]))
I have got this far with the linq to entity statement:
var rooms = (from r in db.Rooms
where !(((from b in db.Bookings
where (startDate >= b.StartDate && endDate <= b.EndDate) || (endDate >= b.StartDate && endDate <= b.EndDate)).Contains(r.RoomID))
select new AvailableRoom
{
ID = r.RoomID,
Size = r.RoomSize
});
I get an error at the last bracket before .Contains(r.RoomID) saying I should have a select statement but I just can't seem to get it working.
Any suggestions would be welcome.
If you reckon using lambdas would be better/easier please feel free to suggest and example. I'm just not too familiar with them myself.. yet.
Thank you.
You can use LINQ !...Any() for the SQL NOT IN(), like so :
var rooms = (from r in db.Rooms
where !db.Bookings
.Where(b => (startDate >= b.StartDate && endDate <= b.EndDate)
||
(endDate >= b.StartDate && endDate <= b.EndDate)
)
.Any(b => b.RoomID == r.RoomID)
select new AvailableRoom
{
ID = r.RoomID,
Size = r.RoomSize
});

Categories