I have a Linq expression that (for northwind) gets the total qty ordered per product for customer id 'ALFKI'
from od in db.OrderDetails
where od.Order.CustomerID == "ALFKI"
group od by od.Product.ProductName into g1
select new { ProductName = g1.Key, Total = g1.Sum(od => od.Quantity) }
This is fine but to fully understand Linq, I want to try and formulate the expression in a world where Linq2Sql doesn't nicely build the property bridges through foreign keys.
For instance, in the above expression, I'm accessing od.Order.CustomerID. I want to assume that od.OrderID is as far as I can go.
Looking at the SQL for the expression, I have:
SELECT SUM(CONVERT(Int,[t0].[Quantity])) AS [Total], [t2].[ProductName]
FROM [Order Details] AS [t0]
INNER JOIN [Orders] AS [t1] ON [t1].[OrderID] = [t0].[OrderID]
INNER JOIN [Products] AS [t2] ON [t2].[ProductID] = [t0].[ProductID]
WHERE [t1].[CustomerID] = #p0
GROUP BY [t2].[ProductName]
This is as far as I've managed to get:
from od in db.OrderDetails
join o in db.Orders on od.OrderID equals o.OrderID
join p in db.Products on od.ProductID equals p.ProductID
where o.CustomerID == "ALFKI"
group od by od.ProductID into g1
select new { ProductName = g1.Key, Total = g1.Sum(od => od.Quantity) }
This is almost there but g1.Key is referring to the ProductID. I can't seem to get at the ProductName and the order quantity at the same time.
Thanks
Try creating a new anonymous type for your group by:
from od in db.OrderDetails
join o in db.Orders on od.OrderID equals o.OrderID
join p in db.Products on od.ProductID equals p.ProductID
where o.CustomerID == "ALFKI"
group od by new { p.ProductID, p.ProductName } into g1
select new {
ProductName = g1.Key.ProductName,
Total = g1.Sum(od => od.Quantity) }
As well as Kevin's answer, using a composite key, I also managed to do it another way:
from item in (from od in db.OrderDetails
join o in db.Orders on od.OrderID equals o.OrderID
join p in db.Products on od.ProductID equals p.ProductID
where o.CustomerID == "ALFKI"
select new {ProductName = p.ProductName, Quantity = od.Quantity }
)
group item by item.ProductName into g1
select new {ProductName = g1.Key, Total = g1.Sum(od=>od.Quantity) }
More generally, if you want to splice all the joins together and refer to any field:
from item in (from od in db.OrderDetails
join o in db.Orders on od.OrderID equals o.OrderID
join p in db.Products on od.ProductID equals p.ProductID
where o.CustomerID == "ALFKI"
select new { p, od }
)
group item by item.p.ProductName into g1
select new { ProductName = g1.Key, Total = g1.Sum(all => all.od.Quantity)}
Related
There is a table I want to join with different columns in different tables.
This is how so far I did this
var purchData = (from a in db.AppRequest
join e in db.Employee on a.Req_By equals e.Id
join c in db.Company on e.CompanyId equals c.Id
join d in db.Designation on e.DesignId equals d.Id
join l in db.Master_Locations on a.Req_Location equals l.Id
join dep in db.Department on e.DepId equals dep.Id
join p in db.Purchase on a.Id equals p.Req_Id
join pi in db.PurchasingItems on p.Id equals pi.Purchase_Id
join pd in db.PurchasingDetails on p.Id equals pd.Purchase_Id
join pds in db.PurchasingDetailsSup on pd.Id equals pds.PurchasingDetails_Id
join s in db.M_Supplier on pds.Supp_Id equals s.Id
join payMethod in db.Master_PayMethods on s.Pay_Method equals payMethod.Id
join poNo in db.ApprovedPoNumbers on p.Id equals poNo.Purchase_Id
where a.Id == id && pds.IsApproved == true
In db.ApprovedPoNumbers table has purchase_Id and Supplier_Id
In db.PurchasingDetailsSup table has purchase_Id and Supplier_Id
So I want to know that here join poNo in db.ApprovedPoNumbers on p.Id equals poNo.Purchase_Id line I want to join the db.ApprovedPoNumbers table purchase_Id,Supplier_Id with db.PurchasingDetailsSup table purchase_Id and Supplier_Id
You can achieve that by building two objects with the criterias you intend to match and use the equals operator on them:
on new {poNo.purchase_Id, poNo.Supplied_Id} equals new {pds.purchase_Id, pds.Supplier_Id} into details
I am asking for your help regarding a linq query to SQL.
Here is a part of the diagram of my database: https://imgur.com/xFBUm3q
My problem is in the following relationship: tbl_607_bottle and tbl_607_gaz_reporting, I can have several reportings for a bottle but reporting can only have one bottle.
I do this request but it's not satisfying.
var GazReportingWizardViewModel =
(from gr in db.tbl_607_gaz_reporting
join a in db.tbl_607_actors on gr.FK_ID_actors equals a.id
join bo in db.tbl_607_bottle on gr.FK_ID_bottle equals bo.ID
join loc in db.tbl_607_location on bo.FK_ID_location equals loc.ID
join cc in db.tbl_607_conformity_certificate on bo.FK_ID_conformity_certificate equals cc.ID
join j in db.tbl_607_join_bottle_gaz on bo.ID equals j.FK_ID_bottle
join g in db.tbl_607_gaz on j.FK_ID_gaz equals g.ID
join od in db.tbl_607_order_details on g.FK_ID_order_details equals od.ID
where loc.ID == Process
select new GazReportingWizardViewModel
{
bottle_conti_number = bo.bottle_conti_number,
pressure_value = gr.pressure_value,
reporting_date = gr.reporting_date,
first_name = gr.tbl_607_actors.first_name,
last_name = gr.tbl_607_actors.last_name,
expiration_date = cc.expiration_date,
content = od.content_comments
}).Distinct()
.OrderBy(t => t.reporting_date)
.ToList();
I want the last report on each bottle but it return all reports on each bottle.
Would you have an idea of the solution?
Thank you for your time
Thank you so much!
I persisted in trying to solve the problem in a single query when the solution was so simple.
var GazReportingWizardViewModel = (from gr in db.tbl_607_gaz_reporting
join a in db.tbl_607_actors on gr.FK_ID_actors equals a.id
join bo in db.tbl_607_bottle on gr.FK_ID_bottle equals bo.ID
join loc in db.tbl_607_location on bo.FK_ID_location equals loc.ID
join cc in db.tbl_607_conformity_certificate on bo.FK_ID_conformity_certificate equals cc.ID
join j in db.tbl_607_join_bottle_gaz on bo.ID equals j.FK_ID_bottle
join g in db.tbl_607_gaz on j.FK_ID_gaz equals g.ID
join od in db.tbl_607_order_details on g.FK_ID_order_details equals od.ID
where loc.ID == Process
select new GazReportingWizardViewModel
{
bottle_conti_number = bo.bottle_conti_number,
pressure_value = gr.pressure_value,
reporting_date = gr.reporting_date,
first_name = gr.tbl_607_actors.first_name,
last_name = gr.tbl_607_actors.last_name,
expiration_date = cc.expiration_date,
content = od.content_comments
}).ToList();
var res = from element in GazReportingWizardViewModel
group element by element.bottle_conti_number
into groups
select groups.OrderByDescending(p => p.reporting_date).First();
To put it in simple terms i need to write the following SQL in entity framework. I would prefer to do it in Lynq. I'm using mysql
SELECT `p`.`Id`, p.price, p.categoryid, avg(o.rate)
FROM `Product` AS `p`
LEFT JOIN `Order` AS `o` ON `p`.`Id` = `o`.`ProductId`
group by p.id
What I have did so far is below
var data = from p in _context.Product
join o in _context.Order on p.Id equals o.ProductId into orderTemp
from ord in orderTemp.DefaultIfEmpty()
group p by p.Id into gp
select new
{
p.Id,
p.Price,
p.CategoryId,
gp.Average(m => m.Rate)
};
I have been struggling o do this the whole day. Any help would be highly valuable and appreciated. Thank you in advance.
The above is not working, as m is referencing the object of Product.
Thank you everyone who tried to help me out. After a struggle the below worked for me.
var data = from p in _context.Product
join o in _context.Order on p.Id equals o.ProductId into orderTemp
from ord in orderTemp.DefaultIfEmpty()
group ord by p into gp
select new
{
Id = gp.Key.Id,
Price = gp.Key.Price,
CategoryId = gp.Key.CategoryId,
Rate = gp.Average(m => m == null ? 0 : m.Rate)
};
You can try this to find the average from your order table, here the thing is you need select the left outer join result and then do grouping up on it.
(from p in products
join o in Orders on p.id equals o.productId
into pg
from g in pg.DefaultIfEmpty()
select new { p.id, p.categoryId, p.price, g?.rate} into lg
group lg by lg.id into sg
from s in sg
select new { s.id, s.price, rate =sg.Average(r=> r.rate)}).Distinct().ToList();
Can someone please help me convert this SQL to linq or lambda c#
select
count(s.ClassId) [StudentInClass], c.Name [Class], t.Name [teacher]
from
[dbo].[Students] s
inner join
class c on s.ClassId = c.Id
inner join Teacher t
on t.Id = c.TeacherId
group by
s.ClassId, c.Name, t.Name
so far this is what I have, and i am messing it up. I want to achieve the same results as in my sql query
SchoolEntities db = new SchoolEntities();
var StudentsByCourseId = from s in db.Students
join c in db.Classes on s.ClassId equals c.Id
join t in db.Teachers on c.TeacherId equals t.Id
group c by s.ClassId
into g
select g;
in SQL this is what my reults look like, it counts the students in a class by the teacher
StudentCount Class Teacher
1 Geography Teacher1
1 Biology Teacher1
2 Maths Teacher2
You can use an anonymous class to group by multiple properties.
var StudentsByCourseId = from s in db.Students
join c in db.Classes on s.ClassId equals c.Id
join t in db.Teachers on c.TeacherId equals t.Id
group s by new { s.ClassId, Class = c.Name, Teacher = t.Name }
into g
select new
{
StudentInClass = g.Count(),
g.Key.Class,
g.Key.Teacher,
};
Consider the following fictitious scenario:
How would I go about getting a list of all the categories (distinct or otherwise, it doesn't matter) for each customer, even if a customer hasn't ordered any products?
Also assume that we don't have navigation properties, so we'll need to use manual joins.
This is my attempt which uses nesting:
var customerCategories = from c in context.Customers
join o in context.Orders on c.CustomerId equals o.CustomerId into orders
select new
{
CustomerName = c.Name,
Categories = (from o in orders
join p in context.Products on o.ProductId equals p.ProductId
join cat in context.Category on p.CategoryId equals cat.CategoryId
select cat)
};
Is there a different (possibly better way) to achieve the same outcome?
Alternative: Multiple Left (Group) Joins
var customerCategories = from customer in context.Customers
join o in context.Orders on customer.CustomerId equals o.CustomerId into orders
from order in orders.DefaultIfEmpty()
join p in context.Products on order.ProductId equals p.ProductId into products
from product in products.DefaultIfEmpty()
join cat in context.Categories on product.CategoryId equals cat.CategoryId into categories
select new
{
CustomerName = c.Name,
Categories = categories
};
I recreated your table structure and added some data so that I could get a better idea what you were trying to do. I found a couple of ways to accomplish what you want but I'm just going to add this method. I think it's the most concise and I think it's pretty clear.
Code
var summaries = Customers.GroupJoin(Orders,
cst => cst.Id,
ord => ord.CustomerId,
(cst, ord) => new { Customer = cst, Orders = ord.DefaultIfEmpty() })
.SelectMany(c => c.Orders.Select(o => new
{
CustomerId = c.Customer.Id,
CustomerName = c.Customer.Name,
Categories = Categories.Where(cat => cat.Id == c.Customer.Id)
}));
Output
Table Structure
Table Data
If you need all categories couldn't you just:
Categories = (from c in context.Category
select cat)