can't get the right output from a "group by" - c#

Trying to get the list of product Id's with amount of feedbacks each of them has
Need to count only feedbacks that were given to the product as belonging to specific category (see the SQL script: categoryId == 50). Product can belong to multiple categories.
productId, cnt
14, 0
16, 0
15, 1
09, 2
10, 2
EDIT:
I came up with the LINQ to SQL below, to recreate the logic I expressed trough SQL script below. But the result is not the same. Can't get what's different with LINQ's logic from SQL script's?
LINQ to Sql:
var result =
(
from pcl in db.productCategoryLookup
join p in db.products on pcl.productId equals p.productId
join f in db.feedbacks on p.productId equals f.feedbackId into bb
from g in bb.DefaultIfEmpty()
where (pcl.categoryId == 50)
group p by p.productId into grp
select new
{
productId = grp.Key,
cnt = grp.Count()
} into res1
orderby res1.cnt
select new
{
producetId = res1.productId,
cnt = res1.cnt
}
)
.Take(5)
.ToList();
SQL Script:
SELECT TOP 5
p.productId,
COUNT(f.feedbackId)
FROM ProductCategoryLookup pcl
INNER JOIN Product p
ON p.productId = pcl.productId
LEFT JOIN Feedbacks f
ON f.productId = p.productId
WHERE
pcl.categoryId = 50
GROUP BY
p.productId
ORDER BY
COUNT(f.feedbackId)
Tables:
**Products** table
productId PK
productName string
**ProductCategoryLookup** table. Connects products with Category.
One product can have multiple categories and the feedback goes
for given product in given category.
productId FK
categoryId FK
. . .
**Feedbacks** table. Each product+category pair gets zero or more feedbacks.
feedbackId PK
productId FK
categoryId FK
. . .
**Category** table.
categoryId pk
name
To the answer from AD.Net I added join after 'from' for the productCategoryLookup, and where clause. Works now! Thanks.

(from p in context.Products
select new {Product = p, Count = p.Feedbacks.Any() ? p.Feedbacks.Count() : 0})
.OrderBy(p=>p.Count)
.Take(5)
.Select(p=>p.Product)
.ToList()

Try following query. It may help you.
db.Products.Select(n => new { n.ProductID, count = n.Feedbacks.Count})
.OrderBy(m=>m.count).Take(5).ToList();

Related

How to filter many to many joins in EF Core

I have the structure below:
Product Category
Product (with one Product Category)
ProductComplementCategory (Product has many ProductComplementCategory)
ComplementCategory (ProductComplementCategory has one ComplementCategory)
ComplementCategoryComplements (ComplementCategory has many ComplementCategoryComplements)
Complement (ComplementCategoryComplements has one Complement)
All tables has the property "Active" and I need to select all tables with join but filtering active = 1 in tables Product Category, Product, ComplementCategory and Complement
Query in SQL:
SELECT
pc.*,
p.*,
cc.*,
c.*
FROM
ProductCategory pc
JOIN Product p ON pc.[ Uid ] = p.ProductCategoryId
JOIN ProductComplementCategory pcc ON p.[ Uid ] = pcc.ProductID
JOIN ComplementCategory cc ON pcc.ComplementCategoryID = cc.[ Uid ]
JOIN ComplementCategoryComplements ccc ON cc.[ Uid ] = ccc.ComplementCategoryID
JOIN Complement c ON ccc.ComplementID = c.[ Uid ]
WHERE
pc.Active = 1
AND p.Active = 1
AND cc.Active = 1
AND c.Active = 1
I need to do this query in EF Core!
i hope this would help you
var temp = (
from pc in ProductCategory
join p in Product
on pc.Uid equals p.ProductCategoryId
join pcc in ProductComplementCategory
on pcc on p.Uid equals pcc.ProductID
join permission in ComplementCategory
on pcc.ComplementCategoryID equals cc.Uid
join cc in ComplementCategoryComplements
on cc.Uid equals ccc.ComplementCategoryID
join c in Complement
on ccc.ComplementID equals c.Uid
where pc.Active = 1 && p.Active = 1 && cc.Active = 1 && c.Active = 1
select new { pc,p,pcc,c,cc }
).ToList

How to get average of Categories if SubCategories are referenced in Result table?

I am having problems in writing a LINQ for calculating average value based on not directly referenced column.
Provide background and tell us what you've already tried.
I have following tables, now I want average marks based on category and subcategory, But fetching it through TopicId(FK) in Result table is going to be a big task.
(I tried and couldn't figure out how to do it)
Image having tables
How Can I get average marks for Category and subcategory?
This is the SQL query that you need:
select
c.Id as CategoryId,
c.CategoryName,
sc.Id as SubCategoryId,
sc.SubCategoryName,
AVG(r.Marks) as Average
from Result r
join Topic t on r.TopicId = t.Id
join SubCategory sc on t.SubCategoryId = sc.Id
join Category c on sc.CategoryId = c.Id
group by c.Id, c.CategoryName, sc.Id, sc.SubCategoryName
And this is the same with LINQ query syntax:
using (var db = new TopicContext())
{
// build the query
var query =
from r in db.Result
join t in db.Topic on r.TopicId equals t.Id
join sc in db.SubCategory on t.SubCategoryId equals sc.Id
join c in db.Category on sc.CategoryId equals c.Id
group r by new { c.Id, c.CategoryName, SubCategoryId = sc.Id, sc.SubCategoryName } into gr
select new
{
CategoryId = gr.Key.Id,
CategoryName = gr.Key.CategoryName,
SubCategoryId = gr.Key.SubCategoryId,
SubCategoryName = gr.Key.SubCategoryName,
Average = gr.Average(x => x.Marks)
};
// ToList() method executes the query, so we get the result on that line of code
var result = query.ToList();
}
If you have an existing database you can use EF Core to generate your own dbContext (in my example this is TopicContext class) with the help of Scaffold-DbContext command. You can find an example of this command on that page. To use this command you should install Microsoft.EntityFrameworkCore.Tools nuget package along with Microsoft.EntityFrameworkCore.SqlServer.

Select records count from multiple tables in a single query

I have some models (restaurants, shops, products), and i want to select records count for multiple models in a single linq query.
I know how it should be in sql, but i don't know how to translate it in linq:
select
(select count(*) from restaurants) as restaurantsCount,
(select count(*) from shops) as shopsCount,
(select count(*) from products) as productsCount
from
dual
Considering dual is a dummy table with single row:
var result = new
{
RestaurantsCount = context.Restaurants.Count(),
ShopsCount = context.Shops.Count(),
ProductsCount = context.Products.Count()
};
Single query solution:
var result = from dummyRow in new List<string> { "X" }
join product in context.products on 1 equals 1 into pg
join shop in context.shops on 1 equals 1 into sg
join restaurant in context.restaurants on 1 equals 1 into rg
select new
{
productsCount = pg.Count(),
shopsCount = sg.Count(),
restaurantsCount = rg.Count()
};

LINQ to EF, Left Join and group by clause

I have this SQL:
select o.prod_id, SUM(o.[count]) as [count]
into #otgr
from otgr o
where o.[date]<= #date
group by o.prod_id
select f.prod_id, SUM(f.[count]) as [count]
into #factory
from factory f
where f.[date]<= #date
group by f.prod_id
select p.name, p.id, f.[count] - ISNULL(o.[count],0) as av_count
from products p
join #factory f on f.prod_id = p.id
left join #otgr o on o.prod_id = p.id
where f.[count] - ISNULL(o.[count],0) > 0
How can I translate this into Linq? I'm stuck with this code:
from otgrr in db.otgr
where otgrr.date <= date
group otgrr by otgrr.prod_id into otgrs
from fac in db.factory
where fac.date <= date
group fac by fac.prod_id into facs
from prod in db.products
join fac2 in facs on prod.id equals fac2.Key
join otg2 in otgrs.DefaultIfEmpty(new {id = 0, av_count = 0 }) on prod.id equals otg2.Key
where (fac2.SUM(a=>a.av_count) - otg2.SUM(a=>a.av_count)) > 0
select new products { id = prod.id, name = prod.name, av_count = (fac2.SUM(a=>a.av_count) - otg2.SUM(a=>a.av_count))
Thank to everyone, and sorry for my bad english
You can also check LINQPad.
Of course, you can split this into multiple LINQ queries (after all, the execution is deferred, so it will be executed all as one single query, without using temporary tables. It should be faster in 99% of the cases).
But in your case it can be written more simply, by using navigation properties you probably have already set up:
var result= from p in products
select new {Name=p.Name,
Id = p.Id,
Count = p.Factories.Where(f=> f.date <= date).Sum(f=>f.Count)
- p.otgrs.Where(o=> o.date <= date).Sum(o=>o.Count)
};

in LINQ to SQL how would i create an outer left join to the first element of the right table?

I have two tables Orders and Products where Orders has a ProductID as a forgin key,
I would like to select all products, if a product has orders i would like to select the one with the highest distance field.
thanks,
Your question seems a bit unclear. However, I am assuming that your orders table has a 'distance' column. You would like to select all products with the order that has the highest distance value.
var products = from p in db.Products
select new
{
ProductID = p.ProductID,
ProductName = p.ProductName,
HighestDistanceOrder = p.Orders.OrderByDescending(o => o.Distance).FirstOrDefault()
};
If you wanted the value of highest distance and not the entire order, then
var products = from p in db.Products
select new
{
ProductID = p.ProductID,
ProductName = p.ProductName,
HighestDistance = p.Orders.Max(o => o.Distance)
};
Hope that helps.
Matrich

Categories

Resources