Convert SQL query using 'count' clause, to LinQ - c#

My SQL Server query (below) works perfectly fine, and I'm trying to convert it to LinQ in C#.
SQL Query:
SELECT addressline3, city, COUNT(*) as 'InstitutionNumber'
FROM institutionenquiries
WHERE CITY = 'AHMEDABAD'
GROUP BY addressline3, city
ORDER BY city;
Desired output is:
I'm able to draw the LinQ query in below format, which gives me correct output
(except for COUNT(*) as 'InstitutionNumber').
LINQ Query:
var obj = (from u in dbContext.InstitutionEnquiry
where u.City == data.Trim().ToLower()
select new {
AddressLine3 = u.AddressLine3.Trim().ToLower(),
City = u.City.Trim().ToLower(),
InstitutionNumber = (from a in dbContext.InstitutionEnquiry
where a.City == data.Trim().ToLower()
select a).Count()
}).ToList();
This gives me count for 'InstitutionNumber' = 3 for all.
I'm not able to get the count aspect correctly. I've referred to this post's answer and it gives me only count, but I'm not able to nest it within my LinQ query.
Any helpful inputs will be appreciated.

The first observation is that since SQL has a GROUP BY, LINQ should have a GroupBy, too.
The second observation is that since non-aggregate columns in SQL are group by columns, the results you select in LINQ would come from the group's key.
Now we can write the query:
var res = dbContext.InstitutionEnquiry
.Where(u => u.City == data.Trim().ToLower())
.GroupBy(u => new {
AddressLine3 = u.AddressLine3.Trim().ToLower(),
City = u.City.Trim().ToLower()
}).Select(g => new {
g.Key.AddressLine3,
g.Key.City,
Count = g.Count()
}).ToList();

I think you can use this LinQ :
var obj = dbContext.InstitutionEnquiry
// WHERE CITY = 'AHMEDABAD'
.Where(w => w.City == "AHMEDABAD") // => Note
// GROUP BY addressline3, city
.GroupBy(g => new {g.AddressLine3, g.City})
// SELECT addressline3, city, COUNT(*) as 'InstitutionNumber'
.Select(c => new {c.Key.AddressLine3, c.Key.City, InstitutionNumber = c.Count()})
// ORDER BY city
.OrderBy(o=> o.City)
.ToList();
Note: For ignoring case sensitivity You can use :
.Where(string.Equals(w.City.Trim(), data.Trim(), StringComparison.CurrentCultureIgnoreCase))

LINQ :
var obj = (from p in dbContext.InstitutionEnquiry
group p by new
{
p.addressline3,
p.city
} into grp
select new
{
grp.Key.addressline3,
grp.Key.city,
InstitutionNumber = grp.Count(),
}).ToList();
Equivalent Lambda expression :
var obj = dbContext.InstitutionEnquiry
.GroupBy(p => new { p.addressline3, p.city})
.Select(p => new { p.Key.addressline3, p.Key.city, InstitutionNumber = p.Count() })
.ToList();

Related

Slow LINQ query because of Where+ToDictionary

I have this query that I need to run:
IEnumerable<MerchantWithParameters> merchants =
from i in (
from m in d.GetTable<Merchant>()
join mtp in d.GetTable<MerchantToParameters>() on m.Id equals mtp.MerchantId into mtps
from mtp in mtps.DefaultIfEmpty()
join cp in d.GetTable<ContextParameters>() on mtp.ContextParametersId equals cp.Id into cps
from cp in cps.DefaultIfEmpty()
select new {Merchant = m, ContextParameter = cp}
)
group i by new { i.Merchant.Id } into ig
select new MerchantWithParameters()
{
Id = ig.Key.Id,
Parameters = ig.Where(g => g.ContextParameter != null).ToDictionary(g => g.ContextParameter.Key, g => g.ContextParameter.Text)
};
For some reason it takes really long time for this query to be completed.
I believe that it has something to do with
Parameters = ig.Where(g => g.ContextParameter != null).ToDictionary(g => g.ContextParameter.Key, g => g.ContextParameter.Text)
Because when I remove this line, query starts to execute really fast.
Could you please show me what am I doing wrong?
UPDATE:
I am using ToList() to extract data from the database.
It is known SQL limitation. You cannot get grouped items, only grouping key or aggregation result. Since you need all records, we can do grouping on the client side, but previously maximally limit retrieved data.
var query =
from m in d.GetTable<Merchant>()
from mtp in d.GetTable<MerchantToParameters>().LeftJoin(mtp => m.Id == mtp.MerchantId)
from cp in d.GetTable<ContextParameters>().LeftJoin(cp => mtp.ContextParametersId == cp.Id)
select new
{
MerchantId = m.Id,
ContextParameterKey = (int?)cp.Key,
ContextParameterText = cp.Text
};
var result =
from q in query.AsEnumerable()
group q by q.MerchantId into g
select new MerchantWithParameters
{
Id = g.Key,
Parameters = g.Where(g => g.ContextParameterKey != null)
.ToDictionary(g => g.ContextParameterKey.Value, g => g.ContextParameterText)
};
var merchants = result.ToList();

Linq Dynamic Query With Group By

I need extra where clause for my Linq query. For example if customer choose a date filter so i need to date filter to my query etc... When i try to myQuery.Where predicate there is visible just group by's field.
How can i append new where condition to my query.
//for example i need dynamically append o.OrderDate==Datetime.Now or another where clause
var myQuery =(from o in _db.Orders
join l in _db.OrderLines.Where(x => x.ParaBirimi == model.ParaBirimi) on o.orderId equals
l.OrderId
where o.OrderDate.Value.Year == year1
group o by new {o.OrderDate.Value.Month}
into g
select
new
{
Month = g.Key.Month,
Total = g.Select(t => t.OrderLines.Sum(s => s.OrderTotal)).FirstOrDefault()
});
You are too late at the end of the query to add new Where. You have already grouped the data, and projected it, removing nearly all the fields.
Try:
var baseQuery = from o in _db.Orders
join l in _db.OrderLines.Where(x => x.ParaBirimi == model.ParaBirimi) on o.orderId equals l.OrderId
where o.OrderDate.Value.Year == year1
select new { Order = o, OrderLine = l };
if (something)
{
baseQuery = baseQuery.Where(x => x.Order.Foo == "Bar");
}
var myQuery = (from o in baseQuery
group o by new { o.Order.OrderDate.Value.Month }
into g
select
new
{
Month = g.Key.Month,
Total = g.Sum(t => t.OrderLine.OrderTotal)
});
Clearly you can have multiple if. Each .Where() is in && (AND) with the other conditions.
Note how the result of the join is projected in an anonymous class that has two properties: Order and OrderLine

Linq query with Contains having null value

var qry = from _Cr in _er.Courses
from _R in _er.ResultsHeaders
where _R.Studentid == studentid
&& !_Cr.CourseID.Contains( _R.CourseID )
select new Obj_getCourses
{
Courseid = _Cr.CourseID,
CourseName = _Cr.CourseName
};
_er.CoursesTable have 4 values in it and _er.ResultsHeader table is empty. I was expecting 4 values from query but the query is not returning any Value. This is the query I am trying to write in LINQ.
Select * \
from Courses \
where courseid not in (Select courseid from ResultsHeader where studentid = 123);
Help require.
Thanks in advance
This should give you your desired results. I have written it in C# statement style so hopefully that having it is LINQ style was not a pre-requisite...
var qry = _er.Courses
.Where( c => !c.CourseID.Contains(_er.ResultsHeader
.Where( r => r.StudentID == 123)
.Select(r => r.CourseID)
)
.Select(c => new Obj_getCourses
{
Courseid = c.CourseID,
Coursename = c.CourseName
});
To get SQL you posted, you should try following query:
var qry = from _Cr in _er.Courses
where !_er.ResultsHeader.Where(r => r.StudentId == studentId)
.Select(r => r.CourseID)
.Contains(_Cr.CourseID)
select new Obj_getCourses
{
Courseid = _Cr.CourseID,
CourseName = _Cr.CourseName
};

Cannot Group By on multiple columns and Count

I want to write this simple query with Linq:
select issuercode,securitycode,dataprocessingflag,COUNT(issuercode) as cnt
from cmr_invhdr
where ProcessedLike <> 'STMNT ONLY'
group by issuercode,securitycode,dataprocessingflag
order by Issuercode
I've tried the following code but I get this error( DbExpressionBinding requires an input expression with a collection ResultType.
Parameter name: input) :
var lstCMRInvHdrNips = (from r in e.CMR_INVHDR
where r.ProcessedLike != "STMNT ONLY"
select new {
r.IssuerCode,
r.SecurityCode,
CountofIssuerCode = r.IssuerCode.Count(),
r.DataProcessingFlag
}
).GroupBy(x =>
new {
x.IssuerCode,
x.SecurityCode,
x.DataProcessingFlag,
x.CountofIssuerCode
}
).OrderBy(x => x.Key.IssuerCode).ToList();
Is there any sense to count issuercode while grouping by this field at once? As when groupped by a field, it's COUNT will always be 1.
Probably you should not group by issuercode and count it after the GroupBy in a separate Select statement:
var result = e.CMR_INVHDR
.Where(r => r.ProcessedLike != "STMNT ONLY")
.GroupBy(r => new { r.SecurityCode, r.DataProcessingFlag })
.Select(r => new
{
Value = r.Key,
IssuerCodesCount = r.GroupBy(g => g.IssuerCode).Count()
})
.ToList();

Translate SQL to lambda LINQ with GroupBy and Average

I spend a few hours trying to translate simple SQL to lambda LINQ
SELECT ID, AVG(Score) FROM myTable
GROUP BY ID
Any idea?
from t in myTable
group t by new {
t.ID
} into g
select new {
Average = g.Average(p => p.Score),
g.Key.ID
}
or Lambda
myTable.GroupBy(t => new {ID = t.ID})
.Select (g => new {
Average = g.Average (p => p.Score),
ID = g.Key.ID
})
The equivalent in Linq-to-Objects would be something like the below.
var results = from row in myTable
group row by row.Id into rows
select new
{
Id = rows.Key,
AverageScore = rows.Average(row => row.Score)
};
It's only slightly different for an ORM like entity framework. Namely, you would need to go through the data context or an appropriate DbSet/ObjectSet.
var _result = from a in myTable
group a by a.ID into g
select new
{
ID = g.Key.ID,
AverageResult = g.Average(x => x.Score)
}

Categories