LINQ Join With Multiple Where Clause - linq

I am struggling once again so any help would be gratefully received.
I have the following LINQ that pulls back a list of data:
public static List<tblWeight> GetWeights(string memberid, string locationid, string buyer, string subcategory, string product)
{
MyEntity getweights = new MyEntity ();
var r = (from p in getweights.tblWeights
where p.MemberId == memberid &&
p.LocationId == locationid
select p);
if (buyer != "Not Specified")
r = r.Where(p => p.UnitUserField1 == buyer);
if (subcategory != "Not Specified")
r = r.Where(p => p.UnitUserField2 == subcategory);
if (product != "Not Specified")
r = r.Where(p => p.IDDesc == product);
return r.ToList();
}
Lovely!
What I would like to do now is based upon this result set and the unit IDs (IDDesc), I then go to tblPurchase, pull back a few columns from tblPurchases and group the columns.
So for example, we have tblWeight looking like so:
MemberID LocationID Buyer SubCategory IDDesc
1 1 Cat1 Sub1 ab
1 1 Cat1 Sub1 abc
1 1 Cat1 Sub2 abcd
The user makes a search for Sub1 in subcategory and the above LINQ does the trick and pulls back the first two rows from above. Fine.
What I need the LINQ to do now is to go to tblPurchases:
MemberID LocationID IDDesc SupplierID SupplierStatus
1 1 ab Sup1 Live
1 1 abc Sup1 Live
1 1 abcd Sup2 Dead
And then pull back the following result so it is joined on MemberID, LocationID and IDDesc but just selects tblPurchases.
Sup1 Live (or all columns in tblPurchases, just grouped/distinct)
I have tried to add in a join and on but no matter how many different variations, I still come across the red squiggle of doom!!!
If anyone can help, beer/kiss is on offer again.

The following LINQ query should do what you want:
var result = from w in tblWeight
where w.SubCategory == "Sub1"
join p in tblPurchases on
new { w.MemberID, w.LocationID, w.IDDesc } equals
new { p.MemberID, p.LocationID, p.IDDesc }
group p by new { p.SupplierID, p.SupplierStatus } into pg
select pg.Key;
The variable result is a list containing tuples of SupplierID and SupplierStatus.
If you also want to put the conditional parts in there, it gets a little more complicated. Here's how to do it:
var weights = from w in tblWeight
select w;
weights = weights.Where(w => w.SubCategory == "Sub1");
// You can add additional where clauses here.
// Now join with tblPurchases and group by SupplierID and SupplierStatus.
var result =
weights.Join(tblPurchases,
w => new { w.MemberID, w.LocationID, w.IDDesc },
p => new { p.MemberID, p.LocationID, p.IDDesc },
(w, p) => p)
.GroupBy(p => new { p.SupplierID, p.SupplierStatus },
(k, ps) => new
{
k.SupplierID,
k.SupplierStatus,
TotalQty = ps.Sum(p => p.PurchaseQty)
});

Related

how use multiple join in linq?

var abc1 = from dlist in db.DebtorTransactions.ToList()
join war in db.Warranties on dlist.ProductID equals war.Id
join ag in db.Agents on war.fldAgentID equals ag.pkfAgentID
join sr in db.SalesReps on war.fldSrId equals sr.pkfSrID
where dlist.TransTypeID == 1
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt1 = abc1.Sum(x => x.Key.Amount);
var abc2 = from dlist in db.DebtorTransactions.ToList()
join cjt in db.CarJackaTrackas on dlist.ProductID equals cjt.pkfCjtID
join ag in db.Agents on cjt.AgentID equals ag.pkfAgentID
join sr in db.SalesReps on cjt.SalesRepId equals sr.pkfSrID
where dlist.TransTypeID == 0
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
enter code here` salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt2 = abc1.Sum(x => x.Key.Amount);
//var result1=
return View();
i am new to linq, this query is working but i need to get the sum of Amount where dlist.TransTypeID == 0 and where dlist.TransTypeID == 1 by just single query. may anybody help me? thanks in advance
Here's a trimmed down example of how you can do it. You can add the joins if they are necessary, but I'm not clear on why you need some of the extra join values.
var transTypeAmountSums = (from dlist in db.DebtorTransactions
group dlist by dlist.TransTypeId into g
where g.Key == 0 || g.Key == 1
select new
{
TransTypeId = g.Key,
AmountSum = g.Sum(d => d.Amount)
}).ToDictionary(k => k.TransTypeId, v => v.AmountSum);
int transTypeZeroSum = transTypeAmountSums[0];
int transTypeOneSum = transTypeAmountSums[1];
A couple of things to note:
I removed ToList(). Unless you want to bring ALL DebtorTransactions into memory then run a Linq operation on those results, you'll want to leave that out and let SQL take care of the aggregation (it's much better at it than C#).
I grouped by dlist.TransTypeId only. You can still group by more fields if you need that, but it was unclear in the example why they were needed so I just made a simplified example.

How can I get the top categories by join in LINQ?

I am working on classified ads project I am facing problem to get top categories where most ads are posted every category have sub category also.
I made query but it is working for sub category ads I want if any category have no sub category then parent category ads should counted.
var result = (from c in db.Category
join a in db.Ad on c.CategoryId equals a.CategoryId
where c.ParentId != null
group c by c.ParentId into g
select new { cat = g.Key, a = g.Count() })
.OrderBy(c => c.cat)
.OrderByDescending(a => a.a);
My Category Table is like this
CategoryId ----- ParentId -----Name
How can I do this?
I guess this could be done with separate queries:
Get a list of categories that don't have any parentId set:
var resultsWithoutSubs = from c in db.Category
where c.ParentId == null
&& !result.Any(r => cat == c.CategoryId)
select c;
Based on the list above, repeat the original query:
var counts = from c in resultsWithoutSubs
join a in dbAd on c.CategoryId equals a.CategoryId
group c by c.CategoryId into g
select new {cat = g. Key, a = g.Count};
Then you should be able to Union these the first and the last list and sort the results.
Try this:
var results = db.Category
.Join(db.Ad, cat => cat.CategoryId,
ad => ad.CategoryId, (cat, ad) => new { cat, ad } )
.Where (c => !dbCategory
.Any (d => c.cat.CategoryId == d.ParentId) && c.cat.ParentId == null)
.GroupBy (c => c.cat.CategoryId)
.Select (g => new
{ cat = g.Key, a = g.Count () }
);

Doing 2 Left Joins on the same table with one call

I have the following tables:
Users:
userId, userFirstName, userLastName.
holdBilling:
bEntityID, CarrierOID, PayerOID, holdTYPE, createUserID.
carrier:
carrierOID, carrierName.
payer:
payerOID, payerName.
I want the code to save in a new entity
holdBilling => new
{
FirstName, LastName, CarrierName, PayerName
}
One of these Entities has either a payer or a carrier value (cannot have both). Basically i want to make 2 left joins on the same table with one call. This would be the SQL query that would work for me.
SELECT TOP 1000 [ID]
,[bEntityID]
,c.carrierID
,c.carrierName
,p.payerID
,p.payerName
,[holdType] ( this is "C" for carrier and "P" for payer )
FROM .[dbo].[holdBilling] hb
left join dbo.payer p on hb.payerID = p.payerID
left join dbo.carrier c on hb.carrierID = c.carrierID
where [bEntityID] = 378
The temporary solution I've found is getting a list of all Carriers
var listC = (from hold in holdBilling
join u in Users on hold.createUserID equals u.userID
join c in carrier.DefaultIfEmpty() on hold.carrierID equals c.carrierID
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = c.carrierName,
Payer = ""
}).ToList();
and one for all payers
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = "",
Payer = p.payerName
}).ToList();
and merging the two,I'm confident there has to be a solution for doing both in one query.
Something like this maybe:
var listC = (
from hb in holdBilling
from p in payer.Where(a=>a.payerID==hb.payerID).DefaultIfEmpty()
from c in carrier.Where(a=>a.carrierID=hb.carrierID).DefaultIfEmpty()
where hb.bEntityID==378
select new
{
hb.bEntityID,
c.carrierID,
c.carrierName,
p.payerID,
p.payerName,
holdType=(payer==null?"P":"C")
}
).Take(1000)
.ToList();
You need to use DefaultIfEmpty to do a left join
var listC = (from hold in holdBilling
from u in Users.Where(x => hold.createUserID == x.userID).DefaultIfEmpty()
from c in carrier.Where(x => hold.carrierID == x.carrierID).DefaultIfEmpty()
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = c.carrierName,
Payer = ""
}).ToList();

Aggregate functions in LINQ

I have the following LINQ conditional where clause query that produces a result of weights:
From this, I'd like to take the result set and join on another table, tblPurchases
var result = weights.Join(getsuppliersproducts.tblPurchases,
w => new { w.MemberId, w.MemberName, w.LocationId, w.UnitId },
p => new { p.MemberId, p.MemberName, p.LocationId, p.UnitId },
(w, p) => p);
In this second table, I have two columns I would like to perform an aggreagte function on, a sum on PurchaseQuantity and a count of UnitID.
So in its raw format, tblPurchases would look like so:
MemberID LocationID UnitId SupplierID SupplierStatus Purchases
1 1 ab Sup1 Live 10
1 1 abc Sup1 Live 10
1 1 abcd Sup2 Dead 50
From my results data set, I would like the output to look like so:
MemberID LocationID SupplierID SupplierStatus UnitIdCount Total Purchases
1 1 Sup1 Live 2 50
Also, with these amendments, can I still return this to a List?
How do I implement this using LINQ? I have tried, and failed miserably.
(To those who have seen my previous posts, I'm trying to cover all angles so I can fully understand the concept of what is going on in both SQL and LINQ)
That query will return an IEnumerable where each of the Purchases matches the MemberId, MemberName, LocationId and UnitId in the original Weights query. You can only easily do one aggregate at a time, so
var result = weights.Join(getsuppliersproducts.tblPurchases,
w => new { w.MemberId, w.MemberName, w.LocationId, w.UnitId },
p => new { p.MemberId, p.MemberName, p.LocationId, p.UnitId },
(w, p) => p).ToList();
Int32 count = result.Count();
Double quantity = result.Sum(p => p.PurchaseQuantity);
Is that what you're trying to do?
EDIT, after your reply of I would like to reutrn a list of tblPurchases with two new columns, the sum of Purchase Quantity and count of unit ID.
This gives a flat output:
var query = Weights.GroupJoin(
Purchases,
w => new {w.MemberId, w.LocationId},
p => new {p.MemberId, p.LocationId},
(w,p) => new {w.MemberId, w.LocationId, Count = p.Count(), Sum = p.Sum(x => x.Purchases)} );
Note that at the point we do the (w, p) => new {} that w is a single Weight and p is a list of Purchases matching that weight, so you can still keep all of teh (hierarchical) data:
var query = Weights.GroupJoin(
Purchases,
w => new {w.MemberId, w.LocationId},
p => new {p.MemberId, p.LocationId},
(w,p) => new {w.MemberId, w.LocationId, Count = p.Count(), Sum = p.Sum(x => x.Purchases), Purchases = p} );

Update existing list values with values from another query

I have a linq statement which calls a stored proc and returns a list of items and descriptions.
Like so;
var q = from i in doh.usp_Report_PLC()
where i.QTYGood == 0
orderby i.PartNumber
select new Parts() { PartNumber = i.PartNumber, Description = i.Descritpion.TrimEnd() };
I then have another SQL statement which returns the quantities on order and delivery date for each of those items. The Parts class has two other properties to store these. How do I update the existing Parts list with the other two values so that there is one Parts list with all four values?
UPDATE
The following code now brings out results.
var a = from a1 in db.usp_Optos_DaysOnHand_Report_PLC()
where a1.QTYGood == 0
orderby a1.PartNumber
select new Parts() { PartNumber = a1.PartNumber, Description = a1.Descritpion.TrimEnd() };
var b = from b1 in db.POP10110s
join b2 in db.IV00101s on b1.ITEMNMBR equals b2.ITEMNMBR
//from b3 in j1.DefaultIfEmpty()
where b1.POLNESTA == 2 && b1.QTYCANCE == 0
group b1 by new { itemNumber = b2.ITMGEDSC } into g
select new Parts() { PartNumber = g.Key.itemNumber.TrimEnd(), QtyOnOrder = g.Sum(x => Convert.ToInt32(x.QTYORDER)), DeliveryDue = g.Max(x => x.REQDATE).ToShortDateString() };
var joinedList = a.Join(b,
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
QtyOnOrder = oss.QtyOnOrder,
DeliveryDue = oss.DeliveryDue
});
return joinedList.ToList();
Assuming your "other SQL statement" returns PartNumber, Quantity and DeliveryDate, you can join the lists into one:
var joinedList = q.Join(OtherSQLStatement(),
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
Quantity = oss.Quantity,
DeliveryDate = oss.DeliveryDate
}).ToList();
You can actually combine the queries and do this in one join and projection:
var joinedList = doh.usp_Report_PLC().
Where(i => i.QTYGood == 0).
OrderBy(i => i.PartNumber).
Join(OtherSQLStatement(),
i => i.PartNumber,
o => o.PartNumber,
(i, o) =>
new Parts
{
PartNumber = i.PartNumber,
Description = i.Description,
Quantity = o.Quantity,
DeliveryDate = o.DeliveryDate
}).ToList();
And again: I assume you have PartNumber in both returned collections to identify which item belongs to which.
Edit
In this case the LINQ Query syntax would probably be more readable:
var joinedList = from aElem in a
join bElem in b
on aElem.PartNumber equals bElem.PartNumber into joinedAB
from abElem in joinedAB.DefaultIfEmpty()
select new Part
{
PartNumber = aElem.PartNumber,
Description = aElem.Description,
DeliveryDue = abElem == null ? null : abElem.DeliveryDue,
QtyOnOrder = abElem == null ? null : abElem.QtyOnOrder
};
Your DeliveryDue and QtyOnOrder are probably nullable. If not, replace the nulls by your default values. E.g. if you don't have the element in b and want QtyOnOrder to be 0 in the resulting list, change the line to
QtyOnOrder = abElem == null ? 0 : abElem.QtyOnOrder

Resources