How to convert this request to LINQ? - mysql

SELECT StepID, count() as nb FROM Question GROUP BY StepID ORDER by nb;

You should probably go through the basics of LINQ. Microsoft Docs has a whole section dedicated to LINQ: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/
If you have your data in a List called as questions of type, List<Question> then you should be able to convert your Query like this:
var ret = from q in questions
group q by q.StepId into grouped
let count = grouped.Count()
orderby count
select new { StepId = grouped.Key, nb = count };

Query comprehension syntax:
from q in questions
group q by q.StepId into g
select new { StepId = g.Key, Count = g.Count() } into stepCount
orderby stepCount.Count
select stepCount;
Exact same in method syntax (which I prefer, since it can all query syntax can plus more and also often is more compact):
questions
.GroupBy(q => q.StepId)
.Select(g => new { StepId = g.Key, Count = g.Count() })
.OrderBy(stepCount => stepCount.Count)
Variant using another GroupBy overload:
questions
.GroupBy(q => q.StepId, (key, values) => new { StepId = key, Count = values.Count() })
.OrderBy(stepCount => stepCount.Count);

Related

Select in multiple tables using EFCore

I have the MySql tables schema below (resumed):
I need to Select only the category data in a Query using EFCore:
List<CategoryViewModel> viewModel = await _context.Category
.Join(_context.Product_Category, c => c.CategoryId, pc => pc.CategoryId, (c, pc) => new { c, pc })
.Join(_context.Product, cpc => cpc.pc.ProductId, p => p.ProductId, (cpc, p) => new { cpc, p })
.Where(cpcp => cpcp.p.EstablishmentId == paramEstablishmentId) //paramEstablishmentId comes via parameter
.Select(vm => new CategoryViewModel()
{
Id = vm.cpc.pc.category.CategortId,
Name = vm.cpc.pc.category.Name,
Image = vm.cpc.pc.category.ImagePath,
Description = vm.cpc.pc.category.Description
})
.ToListAsync();
But this query always result a list with zero models inside. I guarantee there are values in the database to be returned.
Any Ideia what i'm doing wrong?
Many Thanks!
You should use Include()function instead of join. For eg :
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ToList();
Based on #Flyzzx Answer (many thanks, friend), i've modify my query to:
List<CategoryViewModel> viewModel = await _context.Product_Category
.Where(pc => pc.Product.EstablishmentId == EstablishmentId)
.Include(pc => pc.Product)
.Include(pc => pc.Category)
.Select(c => new CategoryViewModel()
{
Id = c.Category.Id,
Name = c.Category.Name,
Image = c.Category.ImagePath,
Description = c.Category.Description
}).Distinct()
.ToListAsync();
Basically, instead of select Categories, now i select Product_Category and use Include to add Products and Categories, making possible to use the Where Clause.

LINQ to SQL: Parameterized keySelector causes local evaluation in LINQPad

I have a LINQ to SQL function that I'd allow to take the keySelector func as a paremeter:
Func<App, string> keySelector = a => a.Name;
Apps.GroupBy(keySelector).Select(g => new { Key = g.Key, Count = g.Count() }).Dump();
However, when I look at the SQL that gets generated, it's clear that everything past the initial table query is getting evaluated locally, and to make matters worse it's querying every column of the table:
SELECT [t0].[AppId], [t0].[Name], [t0].[PublisherId], [t0].[PlatformId], [t0].[UnifiedAppId]
FROM [apps].[App] AS [t0]
If I instead specify the keySelector function inline, it works as expected:
Apps.GroupBy(a => a.Name).Select(g => new { Key = g.Key, Count = g.Count() }).Dump();
SELECT COUNT(*) AS [Count], [t0].[Name] AS [Key]
FROM [apps].[App] AS [t0]
GROUP BY [t0].[Name]
Any ideas how I can get this to work? Thanks!!
Change your KeySelector to be an Expression
ie
Expression<Func<App, string>> keySelector = a => a.Name;
Apps.GroupBy(keySelector).Select(g => new { Key = g.Key, Count = g.Count() }).Dump();

getting my SQL query to be displayed in LINQ form

I am very new to writing LINQ statements, and I am struggling to write this simple SQL in LINQ form.
SELECT Type, COUNT(*) as [Total Submissions]
FROM Submission
GROUP BY Type
this is my attempt:
var query = from s in db.Submission
group s.Type
Type = s.Type
Total = s.Type.Count()
This is what my output should be:
Type Count of Type
Book 10
Chapter 15
Journal 8
Conference 4
Using LINQ syntax:
var result = from x in db.Submission
group x by x.Type into grp
select new {
Type = grp.Key,
Count = grp.Count()
};
Using lambda syntax:
var result = db.Submission
.GroupBy(x => x.Type)
.Select(x => new {
Type = x.Key,
Count = x.Count()
});

Return multiple aggregate columns in LINQ

I would like to translate the following SQL into LINQ:
SELECT
(Select count(BidID)) as TotalBidNum,
(Select sum(Amount)) as TotalBidVal
FROM Bids
I've tried this:
from b in _dataContext.Bids
select new { TotalBidVal = b.Sum(p => p.Amount), TotalBidNum = b.Count(p => p.BidId) }
but get an error "Bids does not contain a definition for "Sum" and no extension method "Sum" accepting a first argument of type "Bids" could be found.
How can I do this in LINQ?
Thanks
CONCLUDING:
The final answer was:
var ctx = _dataContext.Bids;
var itemsBid = (from b in _dataContext.Bids
select new { TotalBidVal = ctx.Sum(p => p.Amount), TotalBidNum = ctx.Count() }).First();
You can write this query using GroupBy. The Lambda expression is as follows:
var itemsBid = db.Bids
.GroupBy( i => 1)
.Select( g => new
{
TotalBidVal = g.Sum(item => item.Amount),
TotalBidNum = g.Count(item => item.BidId)
});
You could try this out. The variable b is an entity (for every iteration) while ctx is an entityset which has the extension methods you need.
var ctx = _dataContext.Bids;
var result = ctx
.Select( x => new
{
TotalBidVal = ctx.Sum ( p => p.Amount ),
TotalBidNum = ctx.Count( p => p.BidId )
} )
.First();
here's an alternative to scartag's solution:
(from b in _dataContext.Bids.Take(1)
select new
{
TotalBidVal = _dataContext.Bids.Sum(p => p.Amount),
TotalBidNum = _dataContext.Bids.Count()
}).Single();
Although there's no real reason you can't just say:
var result = new
{
TotalBidVal = _dataContext.Bids.Sum(p => p.Amount),
TotalBidNum = _dataContext.Bids.Count()
};
It hits the database twice, but its very readable
You could do it using the Aggregate Clause.
Aggregate t In _dataContext.Bids
Into TotalBidNum = Count(BidID),
TotalBidVal = Sum(Amount)
If you're using Fx4+ or an extension dll for Fx2, you could also benfit from parallelism by using
Aggregate t In _dataContext.Bids.AsParallel

LInq-to-sql dynamic sorting problem

I have a linq-to-sql query over entity that has child entityset that I need to sort on some child fields, i.e. use this query:
var query = from p in context.Patients
let order = p.Lab_Orders.First()
orderby order.Order_Date
select p;
This query runs fine, but how would I modify it to use DLINQ OrderBy method what would I pass as a sorting parameter in run-time?
If by DLINQ you mean Dynamic Query, then you can't use the query expressions like that, you have to use extension methods with lambdas. You can start with a query expression but you have to eventually switch it over to lambda:
IEnumerable<Patient> GetPatients(string orderSortField)
{
var query =
from p in context.Patients
select new
{
Patient = p,
FirstOrder = p.Lab_Orders.First()
};
return p.OrderBy(orderSortField).Select(p => p.Patient);
}
Call it with:
var patientsByOrderDate = GetPatients("FirstOrder.Order_Date");
Use the AsQueryable() after the initial statement -
var query = from p in context.Patients
let order = p.Lab_Orders.First()
select p;
query = query.AsQueryable().OrderBy(x => x.Lab_Orders.First().OrderDate);
Try to add the "OrderBy" to the expression tree:
var query = from p in context.Patients
let order = p.Lab_Orders.First()
select p;
var x = Expression.Parameter(query.ElementType, "x");
string sortName = "order.Order_Date";
var selector = Expression.Lambda(Expression.PropertyOrField(x, sortName), x);
query = query.Provider.CreateQuery(
Expression.Call(typeof(Queryable), "OrderBy",
new Type[] { query.ElementType, selector.Body.Type },
query.Expression, selector)
) as IQueryable<Patients>;
Needs the namespace "System.Linq.Expressions".