Join all the sublists together and grab the first one - c#

I want to be able to pull the last invoice containing a product in a category
Category->Product->Invoice
(from p as Product in cat
where p.InvoiceList.Where(function(o) o.InvoiceDate >= MAX_ONE)
select p.InvoiceList.Where(function(o) o.InvoiceDate >= MAX_ONE)
).FirstOrDefault()
I just can't seem to wrap my head about how to get this done.
EDIT: a sample SQL statement that would accomplish my goal. If only I could translate it...
SELECT TOP 1 i.InvoiceID, i.InvoiceDate, i.TotalAmount
FROM Category as c INNER JOIN
Product as p ON p.categoryID = c.categoryID INNER JOIN
InvoiceProducts as ip ON ip.productID = p.productID INNER JOIN
Invoice as i ON ip.InvoiceID = i.InvoiceID
WHERE c.categoryID = 3
ORDER BY InvoiceDate DESC

cat.SelectMany(p => p.InvoiceList).OrderBy(o => o.InvoiceDate).LastOrDefault();

var lastInvoice = (from i in context.Invoices
.where i.Product.CategoryId == categoryId
.select i)
.OrderByDescending(i=>i.IbvoiceDate)
.FirstOrDefault();

Related

How to write left join, group by and average in c# entity framework Linq

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();

left join linq query in FF4

I have the following SQL Query:
SELECT DISTINCT *
FROM Documents d
LEFT JOIN
Invoices
ON (i.invoicedocumentid = d.id or i.jobsheetdocumentid = d.id)
INNER JOIN
PurchaseOrders PO ON i.poid = PO.id
LEFT JOIN
HelpDeskFaults f
ON f.id = PO.helpDeskFaultId
LEFT JOIN stores s
ON s.id = f.storeid
WHERE s.name = 'Linden Drive'
OR d.id in (
SELECT u.id as 'docid'
FROM documents u
INNER JOIN stores s
ON u.storeid = s.id
WHERE s.name = 'Linden Drive'
)
ORDER BY d.Id
So far my linq query looks like this:
var documents = from doc in context.Documents
from invoice in context.Invoices
join po in context.PurchaseOrders on invoice.PurchaseOrder.PurchaseOrderId equals po.PurchaseOrderId
join hdf in context.HelpDeskFaults on po.HelpdeskFaultId equals hdf.ID into hdfpo
from hs in hdfpo.DefaultIfEmpty()
join store in context.Stores on hs.StoreID equals store.ID into hsstore
from hss in hsstore.DefaultIfEmpty()
where hss.Name.Contains(jobSearchParams.StoreName) && (invoice.InvoiceDocumentId == doc.ID || invoice.JobSheetInvoiceId == doc.ID)
select doc;
But the sql that is produced is nothing like what I expected.
Can anyone give me any pointers of how to improve my linq query.
This is what I would translate your SQL query into
var results =
(from doc in context.Documents
from invoice in (
from inv in context.Invoices
where inv.InvoiceDocumentId == doc.ID || inv.JobSheetInvoiceId == doc.ID
select inv).DefaultIfEmpty()
from hs in invoice.PurchaseOrder.HelpDeskFaults.DefaultIfEmpty()
from hss in hs.Stores.DefaultIfEmpty()
where hss.Name == "Linden Drive" || doc.Store.Name == "Linden Drive"
order by doc.ID
select new
{
Document = doc,
Invoice = invoice,
invoice.PurchaseOrder,
HelpDeskFault = hs,
Store = hss,
}).Distinct();
I included that anonymous class of the 5 entities because your SQL is using Select *. I would recommend changing it to only return the minimum required set of fields.

How to turn a SQL Query Into Linq? "People who viewed this product also viewed this product."

I'm not really that good at linq so im having trouple trying to do groups and order by.
The goal of my query is, When someone is on a product page i want to show a list of products that people also viewed. I'm pretty sure this query is right but i have no idea how to to transfer to linq and get it to work in my C# project.
The Sql Query im trying to change to linq is
select pv.ProductId,p.Name, count(*) as 'ProductCount'
from Products p
join ProductVieweds pv
on p.ProductID = pv.ProductId
where UserId in (
select UserId
from ProductVieweds pv
where ProductID = 1 --The 1 in this example is the product the person is viewing.
)
and p.ProductID != 1 --change this
group by pv.ProductId,p.Name
order by 'ProductCount' desc
What I've been able to do so far.
var sub = (
from p in db.ProductsViewed
where p.ProductId == product.ProductID
select p.UserId).ToList();
var products = (from p in db.Products
join pv in db.ProductsViewed on c.ProductID equals p.ProductId
where p.ProductID != currentProduct.ProductID
where sub.Contains(pv.UserId)
select p).GroupBy(c => c.ProductID).ToList();
PeopleAlsoViewedModel model = new PeopleAlsoViewedModel
{
Products = products,
};
The Model
public class PeopleAlsoViewedModel
{
public IEnumerable<Product> Products { get; set; }
}
So i want to be able to group by Products and order by the count but i dont know how to do this and still get a IEnumerable< Product >. Please any help will be awesome, and if your gonna down vote at least tell me why.
Ok so I figured how to solve my problem and thought i should post it incase anyone reads this later.
The Query will look like this in C#
var products = (from c in db.Products
join p in db.ProductsViewed on c.ProductID equals p.ProductId
where c.ProductID != CurrentProduct.ProductID
where sub.Contains(p.UserId)
group c by c.ProductID into productGrouped
orderby productGrouped.Key
select productGrouped).SelectMany(group => group.Distinct()).ToList();
The SelectMany() turns the List< IGrouping< key, element>> into List< Element> I put distinct because multiple people can view the same product otherwise it returns duplicates.

Convert SQL into LINQ and Lambda

Please is somebody able to help me convert the following SQL query into LINQ
select p.Description,SUM(s.TotalArea) as TotalArea from Stands s
inner join ContractProducts cp on s.Id = cp.StandId
inner join Products p on cp.ProductId = p.Id
where s.EventId = 1
group by p.Description
Thanks in advance
Maybe something like this:
var result= (
from s in db.Stands
join cp in db.ContractProducts
on s.Id equals cp.StandId
join p in db.Products
on cp.ProductId equals p.Id
where s.EventId == 1
group p by p.Description into g
select new
{
Description=g.Key,
TotalArea = g.Sum (x =>x.TotalArea)
}
).ToList();
Where db is the linqdatacontext

Alternative to nesting when performing a left join and multiple inner joins

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)

Categories