Entity Framework equivalent of the following query? - c#

Can someone tell me how to write an EF query that equals to this:
SELECT OI.orderid,
OI.inventoryid,
VP.vendorid
FROM orders O
INNER JOIN orderitems OI
ON O.orderid = OI.orderid
INNER JOIN vendorparts VP
ON VP.inventoryid = OI.inventoryid
WHERE (SELECT Count(*)
FROM vendorparts
INNER JOIN vendors
ON vendorparts.vendorid = vendors.vendorid
AND vendors.candropship = 1
WHERE vendorparts.inventoryid = VP.inventoryid
AND vendorparts.vendorid IN ( 1, 17 )) > 1
I'm trying to do something like this...
var q = from o in _context.Orders
join oi in _context.Orderitems on o.Orderid equals oi.Orderid
join vp in _context.Vendorparts on oi.Inventoryid equals vp.Inventoryid
where (from vp2 in _context.Vendorparts
where vp2.Inventoryid == vp.Inventoryid
select count(*)) > 1
but obviously that is syntatctically not allowed.

Long answer:
var vendorIds = new int[] { 1, 17 };
_context
.Orders
.Join(_context.Orderitems,
o => o.Orderid,
oi => oi.Orderid,
(o, oi) => new { o, oi })
.Join(_context.Vendorparts,
o_oi => o_oi.oi.Inventoryid,
vp => vp.Inventoryid,
(o_oi, vp) => new { o_oi.o, o_oi.oi, vp })
.Where(o_oi_vp => _context.Vendorparts
.Where(vp
=> vp.Inventoryid == o_oi_vp.vp.Inventoryid
&& vendorIds.Contains(vp.Vendorid))
.Join(_context.Vendors.Where(v => v.Candropship),
vp => vp.Vendorid,
v => v.Vendorid,
(vp, v) => new { vp, v })
.Any())
.Select(o_oi_vp => new {
o_oi_vp.oi.orderid,
o_oi_vp.oi.inventoryid,
o_oi_vp.vp.vendorid
});
Short answer: use a stored procedure.

Related

How to make this query with lambda expression in Entity Framework?

This is my SQL query:
select
m.Name, s.Time, t.TheaterNumber
from
Movies m
join
MovieSeanceTheaters mst on mst.MovieId = m.MovieID
join
Theaters t on t.ID = mst.TheaterId
join
Seances s on mst.SeanceId = s.ID
This is my attempt at a Linq query:
var result = (from m in _context.Movies
join mst in _context.MovieSeanceTheaters on m.ID equals mst.MovieId
join t in _context.Theaters on mst.TheaterId equals t.ID
join s in _context.Seances on mst.TheaterId equals s.ID
select new { Film = m.Name, Salon = t.Name, Seans = s.Time }
).ToList();
I made this attempt, but I want to make with lambda for instance:
var result = movieManager.GetAll().Where(x => x.MovieSeanceTheaters)....
I couldn't do that.
If I understand you correctly, you want to rewrite your query from query syntax to method syntax?
Here we are!
var result = _context.Movies
.Join(_context.MovieSeanceTheaters,
m => m.MovieID,
mst => mst.MovieID,
(m, mst) => new
{
m = m,
mst = mst
})
.Join(_context.Theaters,
temp0 => temp0.mst.TheaterID,
t => t.ID,
(temp0, t) =>
new
{
temp0 = temp0,
t = t
})
.Join(_context.Seances,
temp1 => temp1.temp0.mst.TheaterID,
s => s.ID,
(temp1, s) =>
new
{
Film = temp1.temp0.m.Name,
Salon = temp1.t.TheaterNumber,
Seans = s.Time
});
Looks ugly, doesn't it?
Most often, the method syntax is more compact and convenient. But in this case, leave it as is.

Linq to Entities Join, Group, Sum with Northwind Orders

I'm trying to write a linq query which should sum order_detail lines from the Northwind.mdb and then return a summarized total along with a few details of the employee responsible. I'm using LINQpad to test it and this is what I have so far
void Main()
{
var result = (from e in Employees
join o in Orders on e.EmployeeID equals o.EmployeeID
join d in OrderDetails on o.OrderID equals d.OrderID
where o.OrderID == 10250
group new { e, o, d } by new
{
o.OrderID, e.Address, e.BirthDate, e.City, e.Country,
e.LastName, e.FirstName, e.Title, e.TitleOfCourtesy, e.HireDate,
e.Region, e.PostalCode, e.HomePhone,
e.Extension, e.ReportsTo,e.PhotoPath, e.EmployeeID,
d.Quantity, d.UnitPrice, d.Discount
}
into grp select new
{
Name = grp.Key.FirstName + " " + grp.Key.LastName,
OrderID = grp.Key.OrderID,
Address = grp.Key.Address,
SalesTotal = grp.Sum(x => x.d.UnitPrice * x.d.Quantity)
});
result.Dump();
}
Output from LINQPad
I was expecting just one line with a total of 1813.00. Can someone tell me what I'm doing wrong?
You're not grouping at the right level. If you change it to group by the employee, then you should get the right results:
void Main()
{
var result = (from e in Employees
join o in Orders on e.EmployeeID equals o.EmployeeID
join d in OrderDetails on o.OrderID equals d.OrderID
where o.OrderID == 10250
group new { e, o, d } by new
{
e.EmployeeID, e.FirstName, e.LastName, e.Address
}
into grp select new
{
Name = grp.Key.FirstName + " " + grp.Key.LastName,
Address = grp.Key.Address,
SalesTotal = grp.Sum(x => x.d.UnitPrice * x.d.Quantity)
});
result.Dump();
}
If you want one line per Order, group by that too:
void Main()
{
var result = (from e in Employees
join o in Orders on e.EmployeeID equals o.EmployeeID
join d in OrderDetails on o.OrderID equals d.OrderID
where o.OrderID == 10250
group new { e, o, d } by new
{
e.EmployeeID, e.FirstName, e.LastName, e.Address,
o.OrderID
}
into grp select new
{
Name = grp.Key.FirstName + " " + grp.Key.LastName,
OrderID = grp.Key.OrderID,
Address = grp.Key.Address,
SalesTotal = grp.Sum(x => x.d.UnitPrice * x.d.Quantity)
});
result.Dump();
}

Entity Framework Left Join on aggregate query

I have an EF query that contains a number of aggregate sub queries (Count, Sum and Max). There are two problems.
I need the joins on the sub queries to be left joins so that records are returned even if there are no results in the aggregate sub queries. At present, records are only returned if all sub queries return records.
The resulting list of WholesaleCustomerAndAggregateOrders objects that are returned contain a Contact object that needs to also include Addresses and Counties. I added Include(c => c.Addresses.Select(a => a.Country)) to the query but the Contact objects don't contain any Address objects.
Any assistance with either issue would be appreciated. Full query below.
var month1Date = DateTime.Today.AddMonths(-1);
var month3Date = DateTime.Today.AddMonths(-3);
var month6Date = DateTime.Today.AddMonths(-6);
var month12Date = DateTime.Today.AddMonths(-12);
var db = GetNewContext();
var qry = from c in db.Contacts
.Include(c => c.Addresses.Select(a => a.Country))
join orderCount in
(
from o in db.WholesaleOrders
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalOrders = g.Count()
}
) on c.Id equals orderCount.ContactId
join month1Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month1Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month1Value.ContactId
join month3Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month3Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month3Value.ContactId
join month6Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month6Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month6Value.ContactId
join month12Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month12Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month12Value.ContactId
join month12Quantity in
(
from o in db.WholesaleOrders
where o.OrderDate >= month12Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
OrderCount = g.Count()
}
) on c.Id equals month12Quantity.ContactId
join lastOrderDate in
(
from o in db.WholesaleOrders
group o by o.ContactId into g
select new
{
ContactId = g.Key,
LastOrderDate = g.Max(r => r.OrderDate)
}
) on c.Id equals lastOrderDate.ContactId
select new WholesaleCustomerAndAggregateOrders
{
Contact = c,
TotalOrders = orderCount.TotalOrders,
Month1Value = month1Value.TotalValue,
Month3Value = month3Value.TotalValue,
Month6Value = month6Value.TotalValue,
Month12Value = month12Value.TotalValue,
Month12OrderCount = month12Quantity.OrderCount,
LastOrderDate = lastOrderDate.LastOrderDate
};
return await qry.ToListAsync();
How about this:
db.WholesaleOrders
.GroupBy(o => o.ContactId)
.Select(a => new {
a.Key,
TotalOrders = a.Count(),
LastOrderDate = a.Max(r => r.OrderDate),
Month1Value = a.Where(b => b.OrderDate >= month1Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price),
Month3Value = a.Where(b => b.OrderDate >= month3Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price),
Month6Value = a.Where(b => b.OrderDate >= month6Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price),
Month12Value = a.Where(b => b.OrderDate >= month12Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price)
}).ToListAsync();
UPDATE: Add another property to projection:
Addresses = db.Addresses.Where(ad => ad.ContactId == a.Key);
where db is your context, and ad.ContactId is FK of the contact in Address table.
For this to work, multipleactiveresultsets property of the connection must be set to True.

How to write lambda expression for an sql expression?

I have an SQL expression
select S.SpecialtyName, COUNT(distinct SUC.SiteUserId) as Subscribers
from SiteUserContent SUC Inner join
Specialties S on SUC.SpecialtyId = S.SpecialtyId Inner join
SiteUser SU on SUC.SiteUserId = SU.SiteUserId
where SU.DeletedFlag = 0
group by S.SpecialtyName
Order by S.SpecialtyName
What will be the corresponding LINQ expression for the same?
from suc in context.SiteUserContent
join s in context.Specialties on suc.SpecialtyId equals s.SpecialtyId
join su in context.SiteUser on suc.SiteUserId equals su.SiteUserId
where su.DeletedFlag == 0
select new { suc.SiteUserId, s.SpecialityName } into x
group x by x.SpecialityName into g
orderby g.Key
select new {
SpecialityName = g.Key,
Subscribers = g.Select(i => i.SiteUserId).Distinct().Count()
}
Generated SQL will not be same, but I think result of query execution should be same.
var results = contex.SiteUserContent
.Join(context.Specialties, suc => suc.SpecialtyId, s => s.SpecialtyId, (suc, s) => new { suc, s })
.Join(context.SiteUser, i = i.suc.SiteUserId, su => su.SiteUserId, (i, su) => new { suc = i.suc, s = i.s, su = su })
.Where(i => i.su.DeletedFlag == 0)
.GroupBy(i => i.s.SpecialtyName)
.Select(g => new {
SpecialityName = g.Key,
Subscribers = g.Select(i => i.suc.SiteUserId)
.Distinct()
.Count()
})
.OrderBy(i => i.SpecialityName);

Linq outer Join

How do I change this query to an outer join so that customers with no orders still appear in the results?
Customers
.Join(
Orders,
c => c.ID,
r => r.ID,
(c, r) =>
new
{
Name = c.Name,
Address = c.Address,
OrderNumber = r.OrderNumber,
OrderDetails = r.OrderDetails
}
).ToList()
from c in context.Customers
join o in context.order on new { cid = c.cid } equals new { cid = o.cid } into ljoin
from l in ljoin.DefaultIfEmpty()
select new()
{
//whatever
};

Categories