Get Sum of a field in Linq with Group by - c#

I am having an SQL:
SELECT ApplicationNo,COUNT(ApplicationNo) AS CNT, SUM(Amount) as AMNT
FROM Payments where (TYPE=1 AND Position=1) and (Date>='2011-01-01')
and (Date<='2012-01-01')
GROUP BY ApplicationNo
Is there a way in which I can convert the same in Linq?
var q = (from payments in context.Payments
where payments.Date >= fromdate && payments.Date <= todate
group payments by new { payments.ApplicationId } into g
select new
{
applicationId=g.Key,
Amount=g.Sum(a=>a.Amount)
});
If I write the same in Linq and then Group by in the end, I am not getting the same result.

DateTime fromDate = new DateTime(2011, 1, 1);
DateTime toDate = new DateTime(2011, 1, 1);
var query = from p in db.Payments
where p.Type == 1 && p.Position == 1 &&
p.Date >= fromDate && p.Date <= toDate
group p by p.ApplicationNo into g
select new {
ApplicationNo = g.Key,
CNT = g.Count(),
AMNT = g.Sum(x => x.Amount)
};
Here db is your context class.

Related

Group by DATEPART and DATEDIFF in LINQ .netcore 3.1

This SQL query works fine:
SET DATEFIRST 7
select DATEPART(YEAR, e.LogDate) Year,
DATEPART(MONTH, e.LogDate) Month,
DATEPART(DAY, e.LogDate) Day,
DATENAME(WEEKDAY, e.LogDate) DayName,
DATEDIFF(WEEK, 0, e.LogDate) - (DATEDIFF(WEEK, 0, DATEADD(DD, -DAY(e.LogDate) + 1, e.LogDate)) - 1) AS WeekNumber,
e.Client,
e.Status,
COUNT(*) TotalCount from EmployeeProcessLogs as e
where e.Client = 'COUPA' and e.LogDate >= CAST('2020-1-1' AS datetimeoffset) and e.LogDate <= CAST('2021-1-1' AS datetimeoffset)
group by
DATEPART(YEAR, e.LogDate),
DATEPART(MONTH, e.LogDate),
DATEPART(DAY, e.LogDate),
DATENAME(WEEKDAY, e.LogDate),
DATEDIFF(WEEK, 0, e.LogDate) - (DATEDIFF(WEEK, 0, DATEADD(DD, -DAY(e.LogDate) + 1, e.LogDate)) - 1),
e.Client,
e.Status
which give a result of:
How can I get the same result with LinQ?
This is what I've come up so far but it is giving me an error:
var query = from l in _db.EmployeeProcessLogs
where l.Client == client &&
l.LogDate >= fromDate &&
l.LogDate <= toDate
let year = l.LogDate.Year
let month = l.LogDate.Month
let day = l.LogDate.Day
let dayName = l.LogDate.ToString("dddd")
let weekNumber = _.GetWeekNumber(l.LogDate.DateTime)
let clientType = l.Client
let status = l.Status
group l by new
{
Year = year,
Month = month,
Day = day,
DayName = dayName,
WeekNumer = weekNumber,
Client = clientType,
Status = status
} into g
select new
{
Info = g.Key,
Count = g.Count()
};
var hh = query.ToList();
The error says:
The LINQ expression 'DbSet<EmployeeProcessLog>
.Where(e => e.Client == __client_0 && e.LogDate >= __fromDate_1 && e.LogDate <= __toDate_2)
.GroupBy(
source: e => new {
Year = e.LogDate.Year,
Month = e.LogDate.Month,
Day = e.LogDate.Day,
DayName = e.LogDate.ToString("dddd"),
WeekNumer = ____3.GetWeekNumber(e.LogDate.DateTime),
Client = e.Client,
Status = e.Status
},
keySelector: e => e)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
This is the code for GetWeekNumber
public int GetWeekNumber(DateTime date)
{
var gc = new GregorianCalendar();
var firstDate = new DateTime(date.Year, date.Month, 1);
var weekOfYear = gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
var firstWeekOfYear = gc.GetWeekOfYear(firstDate, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
return weekOfYear - firstWeekOfYear + 1;
}

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.

SQL query to LINQ expression

How can I translate this SQL query to a LINQ expression?
select NoteDate, SUM( DurationInHours ) from Note
where IDUser = '2933FB9C-CC61-46DA-916D-57B0D5EF4803' and
NoteDate > '2013-07-01'
group by NoteDate
I tried it, but it didn't work
var lastMonth = DateTime.Today.AddMonths(-1);
var userNotes = GetNotesByUser(idUser);
var b = from note in userNotes
group note by new {note.IDUser, note.NoteDate, note.DurationInHours} into g
where g.Key.NoteDate > lastMonth
select new {g.Key.NoteDate, TotalHours = g.Sum(a => a.DurationInHours)}
var id = new Guid("2933FB9C-CC61-46DA-916D-57B0D5EF4803");
var date = new DateTime(2013, 7, 1);
var query = from n in db.Notes
where n.IDUser == id && n.NoteDate > date
group n by n.NoteDate into g
select new {
NoteDate = g.Key,
Sum = g.Sum(x => x.DurationInHours)
};

This LINQ-to-Entities join seems overly complex, am I doing something wrong?

I have two queries that I need to combine in LINQ that both actually come from the same table. The reason for this is that one of the queries needs to get the max of a field for each day and then sum the days together where the second query can just sum everything right off the bat. Here is the first query:
var queryDownload = from p in
(from p in almdbContext.cl_contact_event
where p.time_of_contact >= startDate && p.time_of_contact < endDate && p.input_file_name.Contains(inputFileName) && listName.Contains(listName)
group p by new
{
date = EntityFunctions.CreateDateTime(p.time_of_contact.Value.Year, p.time_of_contact.Value.Month, p.time_of_contact.Value.Day, 0, 0, 0),
listName = p.contact_list_name
} into g
select new
{
date = g.Key.date,
listName = g.Key.listName,
download = g.Max(a => a.total_number_of_records)
})
group p by p.listName into g
select new
{
listName = g.Key,
totalDownload = g.Sum(a => a.download),
};
This is the second:
var queryPenData = from p in almdbContext.cl_contact_event
where p.time_of_contact >= startDate && p.time_of_contact < endDate && p.input_file_name.Contains(inputFileName) && listName.Contains(listName)
group p by p.contact_list_name into g
select new
{
listName = g.Key,
dials = g.Sum(a => a.ov_dial_start_time != null ? 1 : 0),
agentConnects = g.Sum(a => a.agent_login_name != null ? 1 : 0),
abandons = g.Sum(a => a.response_status == "DAC" || a.response_status == "DAD" ? 1 : 0),
rightPartyContacts = g.Sum(a => a.response_status == "PTP" || a.response_status == "RPC" ? 1 : 0),
promiseToPays = g.Sum(a => a.response_status == "PTP" ? 1 : 0),
talkTime = g.Sum(a => EntityFunctions.DiffSeconds(a.ov_call_connected_time, a.ov_trunk_released_time)) ?? 0,
wrapTime = g.Sum(a => EntityFunctions.DiffSeconds(a.ov_trunk_released_time, a.record_released_time)) ?? 0
};
And this is the query joining them together.
var queryJoin = from qd in queryDownload
join qp in queryPenData
on qd.listName equals qp.listName
select new
{
listName = qp.listName,
download = qd.totalDownload,
dials = qp.dials,
agentConnects = qp.agentConnects,
abandons = qp.abandons,
rightPartyContacts = qp.rightPartyContacts,
promiseToPays = qp.promiseToPays,
talkTime = qp.talkTime,
wrapTime = qp.wrapTime
};
This seems extremely verbose/roundabout to me. Is there a better way I can write/approach this to shrink/simplify the code?
For your last query could you not just do something like this?
var queryJoin = from qd in queryDownload join qpd in queryPenData on qd.listname equals qpd....
Should be able to do this:
var queryJoin = from qd in queryDownload
join qp in queryPenData
on qd.listName equals qp.listName
select new
{
qp, qd
};
From what I can tell you've already formed your data in queryPenData so there is no reason to re-assign it to new variables in the final join. Just select the object which will allow you to traverse into the anonymous type in queryPenData. I think...

How to merge 5 different type of linq queries into one based on a column

I am really confused on a report I need. As of today, most of my reports were simple, so I was able to do them myself easily. But being a newbie in sql/dlinq, I cannot find my way through the following:
var closingStock =
(from p in session.Query<Product>()
select new
{
p.Id,
p.Name,
p.Batch,
p.Rate,
ClosingStock = p.Quantity - p.AllocatedQuantity,
p.DivisionId
}).ToList();
var distributedQuantityAfterPeriod =
(from i in session.Query<OutwardInvoiceItem>()
where i.ParentInvoice.Date > ToDate
select new
{
Id = i.Product.Id,
DistributedAfter = i.Quantity
}).ToList();
var distributedQuantityInPeriod =
(from i in session.Query<OutwardInvoiceItem>()
where i.ParentInvoice.Date >= FromDate && i.ParentInvoice.Date <= ToDate
select new
{
Id = i.Product.Id,
Distributed = i.Quantity
}).ToList();
var receivedQuantityAfterPeriod =
(from i in session.Query<InwardInvoiceItem>()
where i.ParentInvoice.Date > ToDate
select new
{
Id = i.Product.Id,
ReceivedAfter = i.Quantity
}).ToList();
var receivedQuantityInPeriod =
(from i in session.Query<InwardInvoiceItem>()
where i.ParentInvoice.Date >= FromDate && i.ParentInvoice.Date <= ToDate
select new
{
Id = i.Product.Id,
Received = i.Quantity
}).ToList();
As you can see, I am trying to build a inventory movement report for a specific date. I have the following problems:
1. How can I reduce the five queries? Is it possible?
2. How can I merge the data provided by these queries into one table which is grouped on the product id and summed on the quantity related columns? As of now, I am using for loops which are really slow.
What I am using:
C# 4, nHibernate, Sqlite
Any help will be very highly appreciated.
Regards,
Yogesh.
to reduce roundtrips use .Future() instead of .List()
let all queries return
group i by i.Id into g
select new
{
Id = g.Key,
Quantity = g.Sum(x => x.Quantity)
}).Future();
and do
var alltogether = groupedDistributedQuantityAfterPeriod
.Concat(groupedDistributedQuantityInPeriod)
.Concate(...);
from g in alltogether
group g by g.key into all
select new
{
Id = all.Key,
Quantity = all.Sum(x => x.Quantity)
};
Update:
you can reduce the number of queries with
from i in session.Query<OutwardInvoiceItem>()
where (i.ParentInvoice.Date > ToDate) || (i.ParentInvoice.Date >= FromDate && i.ParentInvoice.Date <= ToDate)
select ...
from i in session.Query<InwardInvoiceItem>()
where (i.ParentInvoice.Date > ToDate) || (i.ParentInvoice.Date >= FromDate && i.ParentInvoice.Date <= ToDate)
select ...

Categories