Linq Query Group By Multiple Columns Having Count > 1 - c#

I have a query I know how to do in SQL but struggling to figure out the LINQ query. Here is the SQL.
SELECT ordNo, tranNo, COUNT(distinct custNo)
FROM orders
GROUP BY ordNo, tranNo
HAVING COUNT(distinct custNo) > 1
I don't feel like this is the same question that I see you marked as a duplicate. The linked question only groups on a single property. I've lost track of the Linq queries I've tried but here is one.
var countList = from o in orders
group o by new {o.orderNo, o.tranNo, o.custNo}
into grp
where grp.Key.custNo.Distinct().Count() > 1
select grp;
I tried the suggestion below but like someone commented you can't access the custNo property.

Just spitballing since I don't know the table structure.
context.orders
.GroupBy(o => new { o.ordNo, o.tranNo, o.custNo })
.Where(o => o.custNo.Distinct().Count() > 1)
.Select(o => new {
ordNo = o.ordNo,
tranNo = o.tranNo
});

Related

sql query do in subquery in LINQ

below is my SQL query
SELECT
p.Name
, p.DisplayName
, (
SELECT COUNT(*)
FROM LicenseActivations la
WHERE la.ProductId=p.Id
AND la.AccountId='QWNjb3VudDo2N2YyMTcwMC0xMWZlLTExZWItYjNkMS0yN2U1Mjk0MGVhYmU='
) AS COUNT
FROM [Products] p
GROUP BY p.Name, p.DisplayName, p.id;
here I am using two tables 1.Products 2.LicenseActivations, I need to form LINQ, Can anyone help me out with this one
In Linq you seldom need joins. With a proper database design with relations established, Linq navigation properties does the job (which are generated automatically by the tools for you):
var list = from p in _DbContext.Products
select new {
p.Name,
p.DisplayName,
Count = p.LicenseActivations.Count(x => x.AccountId=="QWNjb3VudDo2N2YyMTcwMC0xMWZlLTExZWItYjNkMS0yN2U1Mjk0MGVhYmU=")
};
is the corresponding Linq query of your SQL (ToList() is optional).
EDIT: If you don't have proper relations in your database, then:
var list = from p in _DbContext.Products
select new {
p.Name,
p.DisplayName,
Count = _DbContext.LicenseActivations
.Count(x => x.ProductId == p.Id &&
x.AccountId=="QWNjb3VudDo2N2YyMTcwMC0xMWZlLTExZWItYjNkMS0yN2U1Mjk0MGVhYmU=")
};

Linq query for top parents by number of childs, including this number

In my model, there are entities Article and Tag in many-to-many relation through table ArticleTag.
I want to select "trending tags" - tags with most articles in last X days, and I want this count too.
Basically, I need help creating EF Linq query equivalent to this SQL query, with ideal result being Dictionary<Tag, int>
SELECT TOP 50
t.Id, t.Name, count(*)
FROM ArticleTag at
JOIN Article a ON a.Id = at.ArticleId
JOIN Tag t ON t.Id = at.TagId
WHERE a.DateCreated > '2019-10-01'
GROUP BY t.Id, t.Name
ORDER BY count(*) DESC
Can this be done without having ArticleTag as DbSet in DbContext (since it is not really an entity, and I dont need it besides this query).
You have to use navigation properties for this query and do not need to know anything about ArticleTag table.
var query =
from a in ctx.Articles
from t in a.Tags
where a.DateCreated > someDate
group t by new { t.Id, t.Name } into g
orderby g.Count() descending
select new
{
g.Key.Id,
g.Key.Name,
Count = g.Count()
};
var result = query
.Take(50)
.ToDictionary(x => new Tag { Id = x.Id, Name = x.Name }, x => x.Count);

Join Error | Unable to create a constant value of type only primitive

Very new with LINQ here.
I have the following data in my table (TableA):
ID Name SubmissionNo
1 Jim A-1
2 Andy A-2
3 Rick A-2
4 Mary A-3
5 Zim A-4
6 Loren A-1
I then need to create a query which will allow me to get from that table, those records which have duplicate submission numbers.
Here's my solution so far (Context is the database context):
var duplicates = (from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
select new { count = grp.Count(), submissionNo = grp.Key})
.Where(x => x.count > 1)
.OrderBy(y => y.submissionNo).ToList();
The variable duplicates then contains the record:
count submissionNo
2 A-1
2 A-2
I then write the main query which will allow me to get all the records from TableA which has duplicate submissionNo
var myList = (from tbl in Context.TableA.AsNoTracking()
join dup in duplicates on tbl.SubmissionNo equals dup.submissionNo
select new
{
ID = tbl.ID,
Name = tbl.Name,
SubmissionNo = tbl.SubmissionNo
})
.ToList();
I am then getting an error for the myList query with
Unable to create a constant value of type 'Anonymous Type'. Only primitive types or enumeration types are supported in this context.
I think there must be a better way to do this as from the TableA above, I practically want the following results:
ID Name SubmissionNo
1 Jim A-1
2 Andy A-2
3 Rick A-2
6 Loren A-1
Your first query, slightly modified, has all information you need:
var myList = from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
where grp.Count() > 1
from item in grp
select new
{
count = grp.Count(),
submissionNo = grp.Key,
item.Name,
);
The pattern group into grp - from item in grp is a commonly used query pattern to group items and then flatten the group again, while keeping in touch with the group data (like Count() and Key).
Now you don't need the join anymore and the exception doesn't occur. By the way, the exception tells you that EF can only handle joins with collections of primitive types (int etc.), because it has to translate the whole expression into SQL. There's simply no translation for rich objects like TableA.
By the way, the query can be improved by removing the repeated Count():
var myList = from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
let count = grp.Count()
where count > 1
from item in grp
select new
{
count = count,
submissionNo = grp.Key,
item.Name,
);
This will generate a more efficient SQL statement containing one COUNT instead of two.
Since Entity Framework does not support joining in-memory collections of objects with database collections, a common workaround for this is to filter using Contains.
First, you need to get the IDs to filter on:
var duplicates = (from tbl in Context.TableA.AsNoTracking()
group tbl by tbl.SubmissionNo into grp
select new { count = grp.Count(), submissionNo = grp.Key})
.Where(x => x.count > 1)
.OrderBy(y => y.submissionNo)
.ToList();
var duplicateIds = duplicates.Select(x => x.submissionNo).ToList();
And then change your query to perform a WHERE...IN instead of a JOIN:
var myList = (from tbl in Context.TableA.AsNoTracking()
where duplicateIDs.Contains(tbl.SubmissionNo)
select new
{
ID = tbl.ID,
Name = tbl.Name,
SubmissionNo = tbl.SubmissionNo
})
.ToList();

Entity Framework grouping by column from join

I have the next query:
select VisitLines.ProcedureId, COUNT(DISTINCT VisitLines.VisitId) as nt
from Visits
LEFT JOIN VisitLines ON Visits.Id = VisitLines.VisitId
WHERE Visits.VisitStatusId = 1 AND Visits.IsActive = 1 AND VisitLines.IsActive = 1
GROUP BY VisitLines.ProcedureId
Main question: Does ability exists to grouping by column from join using linq ? I'm wondering how to do it using 'collection' column.
Is it possible to force EF to generate COUNT(DISTINCT column) ? IQueryable.GroupBy.Select(x => x.Select(n => n.Number).Distinct().Count()) generate query with few subqueries which much slower then COUNT(DISTINCT )
I found. Need to use SelectMany with second parameter resultSelector:
dbContext.Visits.Where(x => x.IsActive)
.SelectMany(x => x.VisitLines, (v, vl) => new
{
v.Id,
vl.ProcedureId
})
.GroupBy(x => x.ProcedureId)
.Select(x => new
{
Id = x.Key,
VisitCount = x.Count()
}).ToArray();
It generates the desired SQL, but with exception that I need distinct count by visit.
And if I change VisitCount = x.Distinct().Count() then EF generates a query with few subqueries again. But the main issue resolved

Linq grouping multiple where condition

I have a query that I wrote in SQL, which works, and I am trying to move this to the appropriate LINQ statement, and can't seem to get it quite right.
The SQL query:
select sku
from Table
group by sku
having count(sku) > 1 and count(distinct(unit)) > 1
and what I have so far with LINQ
var dupCount = (from val in dt.AsEnumerable()
group val by new {sku = val[4]} into grp
where grp.Count() > 1 && grp.unit.Distinct().Count() > 1
select grp).ToList();
I cant seem to figure out how to tell the where within the group to only pull the records with a distinct "unitreserve".
I cant seem to figure out how to tell the where within the group to only pull the records with a distinct "unitreserve".
Select the "unitreverse" field, apply Distinct and then Count it:
where grp.Count() > 1 &&
grp.Select(dr => dr["unitreserve"]).Distinct().Count() > 1

Categories