many to many relationship - linq

I am trying to write a linq to get data from many to many tables.
Here are the tables
Products (ID,Name,Description)
Products_Items (ID,ProductID,Description)
ProductsNeeds (ID,Name)
ProductsItems_Needs (ItemID,NeedsID)
This is the t-sql query
select gPro.Name,gProItems.ShortDescription,gProItems.Description,gNeeds.Name
from Products gPro
join Products_Items gProItems on gPro.ID = gProItems.ProductID
join ProductsItems_Needs gProNeeds on gProNeeds.ItemID = gProItems.ID
join ProductsNeeds gNeeds on gNeeds.ID = gProNeeds.NeedsID
where gProItems.ID = 1
this is the linq
var q = from p in objM.Products
join gpItems in objM.Products_Items on p.ID equals gpItems.ProductID
from needs in gpItems.ProductsNeeds
where gpItems.ID == 1
select p;
This query returns (Products) and it has the Produts_Items but it has not the ProductsNeeds.
What modifications should I do in order each Products_items to have the ProductsNeeds?
Thanks

Finally I found the solution.
The change was that instead of returning Products it returns Product_Items.
var q = from pItems in objM.Products_Items
join p in objM.Products on pItems.ID equals p.ID into joinedProducts
from p in joinedProducts.DefaultIfEmpty()
from needs in pItems.ProductsNeeds
where pItems.ID == 1
select pItems;

Related

Linq query not returning expected results even when using DefaultIfEmpty

I have the following query in one of my Entity Framework Core API controllers:
var plotData = await (from nl in _context.BookList
join ql in _context.PlotList on nl.PlotId equals ql.PlotId
join qc in _context.PlotChoices on ql.PlotId equals qc.PlotId
join nk in _context.BookLinks.DefaultIfEmpty() on qc.ChoiceId equals nk.ChoiceId
where nl.Id == ID
select new
{ .. }
I need it to return all rows even if data doesn't exist in the BookLinks table.
However, it's not returning rows if there is no data data in the BookLinks table for that row.
But this SQL query, from which I'm trying to model from, does return data...it returns nulls if there is no data in BookLinks.
select * from BookList bl
left join PlotList pl ON bl.plotId = bl.plotId
left join PlotChoices pc ON pl.plotId = pc.plotId
left join BookLinks bk ON pc.choiceID = bk.choiceID
where nl.caseID = '2abv1'
From what I read online, adding 'DefaultIfEmpty()' to the end of BookLinks should fix that, but it hasn't.
What am I doing wrong?
Thanks!
When using left join , you can try below code sample :
var plotData = (from nl in _context.BookList
join ql in _context.PlotList on nl.PlotId equals ql.PlotId
join qc in _context.PlotChoices on ql.PlotId equals qc.PlotId
join nk in _context.BookLinks on qc.ChoiceId equals nk.ChoiceId into Details
from m in Details.DefaultIfEmpty()
where nl.Id == ID
select new
{
}).ToList();

Need help converting SQL into LINQ

SELECT ra.ResidentID, ra.RoomID, r.Number, ra.StartDate, p.FacilityID
FROM(
SELECT ResidentID, MAX(StartDate) AS max_start
FROM RoomAssignments
GROUP BY ResidentID
) m
INNER JOIN RoomAssignments ra
ON ra.ResidentID = m.ResidentID
AND ra.StartDate = m.max_start
INNER JOIN Rooms r
ON r.ID = ra.RoomID
INNER JOIN Person p
ON p.ID = ra.ResidentID
inner join ComplianceStage cs
ON cs.Id = p.ComplianceStageID
ORDER BY ra.EndDate DESC
I'm trying to figure out how to convert this to C# using LINQ. I'm brand new with C# and LINQ and can't get my subquery to fire correctly. Any chance one of you wizards can turn the lights on for me?
Update-----------------
I think I've got the jist of it, but am having trouble querying for the max startdate:
var maxQuery =
from mra in RoomAssignments
group mra by mra.ResidentID
select new { mra.ResidentID, mra.StartDate.Max() };
from ra in RoomAssignments
join r in Rooms on ra.RoomID equals r.ID
join p in Persons on ra.ResidentID equals p.ID
where ra.ResidentID == maxQuery.ResidentID
where ra.StartDate == maxQuery.StartDate
orderby ra.ResidentID, ra.StartDate descending
select new {ra.ResidentID, ra.RoomID, r.Number, ra.StartDate, p.FacilityID}
Following my LINQ to SQL Recipe, the conversion is pretty straight forward if you just follow the SQL. The only tricky part is joining the range variable from the subquery for max start date to a new anonymous object from RoomAssignments that matches the field names.
var maxQuery = from mra in RoomAssignments
group mra by mra.ResidentID into mrag
select new { ResidentID = mrag.Key, MaxStart = mrag.Max(mra => mra.StartDate) };
var ans = from m in maxQuery
join ra in RoomAssignments on m equals new { ra.ResidentID, MaxStart = ra.StartDate }
join r in Rooms on ra.RoomID equals r.ID
join p in Persons on ra.ResidentID equals p.ID
join cs in ComplianceStage on p.ComplianceStageID equals cs.Id
orderby ra.EndDate descending
select new {
ra.ResidentID,
ra.RoomID,
r.Number,
ra.StartDate,
p.FacilityID
};

Linq: Orderby when including multiple tables

Currently learning Linq to Entity. I been successful, but came stumped with the orderby clause and its use with multiple tables.
var query = from k in contxt.pages.Include("keywords")
where k.ID == vals.pageId select k;
My understanding with the code above is it creates an inner join where ID is equal to pageId.
So what I am having a difficult time visualizing is how I would perform an orderby on both tables?
I would like to sort on both tables.
I have tried:
var query = from k in contxt.pages.Include("keywords") where k.ID == vals.pageId orderby k.keywords.**?** select k;
The question mark is not supposed to be there. I am showing that the column that I would like to sort by isn't there. Trying this k.Kegwords. doesn't show the column.
I would write a SQL query as follows:
string query = "SELECT pages.page, pages.title, pages.descp, keywords.keyword
FROM pages INNER JOIN keywords ON pages.ID = keywords.pageID
ORDER BY keywords.sort, pages.page";
pages and keywords have a 1 to many relationship, which FK keywords.
Thank you,
deDogs
Here you go.
var result = (from x in pages
join y in keywords on x.ID equals y.pageID
orderby y.sort, x.page
select new
{
x.Page,
x.title,
x.descp,
y.keyword
});

Joining three tables and using a left outer join

I have three tables. Two of them join equally but one will need to join with a left. I'm finding a lot of code to do this in linq but between two tables only.
Here is the SQL code that I'm trying to re-code within LINQ.
SELECT PRSN.NAME
,CO.NAME
,PROD.NAME
FROM PERSON PRSN
INNER JOIN COMPANY CO ON PRSN.PERSON_ID = CO.PERSON_ID
LEFT OUTER JOIN PRODUCT PROD ON PROD.PERSON_ID = PROD.PERSON_ID;
Here is a snippet of LINQ code that I'm using as a base. I'm just not able to piece together the third table (product in my sample SQL) via LINQ and with a left outer join. The sample is between two tables. Thanks for any tips.
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product{Name = String.Empty, CategoryID = 0})
select new { CatName = category.Name, ProdName = item.Name };
Michael
How about this:
var loj = (from prsn in db.People
join co in db.Companies on prsn.Person_ID equals co.Person_ID
join prod in db.Products on prsn.Person_ID equals prod.Person_ID into prods
from x in prods.DefaultIfEmpty()
select new { Person = prsn.NAME, Company = co.NAME, Product = x.NAME })
EDIT: if you want to do a left outer join on all tables, you can do it like this:
var loj = (from prsn in db.People
join co in db.Companies on prsn.Person_ID equals co.Person_ID into comps
from y in comps.DefaultIfEmpty()
join prod in db.Products on prsn.Person_ID equals prod.Person_ID into prods
from x in prods.DefaultIfEmpty()
select new { Person = prsn.NAME, Company = y.NAME, Product = x.NAME })
Taken from another Stackoverflow thread somewhere, there's a more legible way to do this:
var loj = (from prsn in db.People
from co in db.Companies.Where(co => co.Person_ID == prsn.Person_ID).DefaultIfEmpty()
from prod in db.Products.Where(prod => prod.Person_ID == prsn.Person_ID).DefaultIfEmpty()
select new { Person = prsn.NAME, Company = co.NAME, Product = prod.NAME })
This uses a mix of linq query syntax and lambda syntax to what (I believe is) the best result. There's no copious re-aliasing of identifiers, and it's the most concise way to do this that I've seen.

LINQ count query returns a 1 instead of a 0

I have the following view:-
CREATE VIEW tbl_adjudicator_result_view
AS
SELECT a.adjudicator_id, sar.section_adjudicator_role_id, s.section_id, sdr.section_dance_role_id, d.dance_id, c.contact_id,
ro.round_id, r.result_id, c.title, c.first_name, c.last_name, d.name, r.value, ro.type
FROM tbl_adjudicator a
INNER JOIN tbl_section_adjudicator_role sar on sar.section_adjudicator_role2adjudicator = a.adjudicator_id
INNER JOIN tbl_section s on sar.section_adjudicator_role2section = s.section_id
INNER JOIN tbl_section_dance_role sdr on sdr.section_dance_role2section = s.section_id
INNER JOIN tbl_dance d on sdr.section_dance_role2dance = d.dance_id
INNER JOIN tbl_contact c on a.adjudicator2contact = c.contact_id
INNER JOIN tbl_round ro on ro.round2section = s.section_id
LEFT OUTER JOIN tbl_result r on r.result2adjudicator = a.adjudicator_id AND r.result2dance = d.dance_id
When I run the following query directly against the db I get 0 in the count column where there is no result
select adjudicator_id, first_name, COUNT(result_id)
from tbl_adjudicator_result_view arv
where arv.round_id = 16
group by adjudicator_id, first_name
However when I use LINQ query I always get 1 in the Count Column
var query = from arv in db.AdjudicatorResultViews
where arv.round_id == id
group arv by new { arv.adjudicator_id, arv.first_name} into grp
select new AdjudicatorResultViewGroupedByDance
{
AdjudicatorId = grp.Key.adjudicator_id,
FirstName = grp.Key.first_name,
Count = grp.Select(p => p.result_id).Distinct().Count()
};
What do I need to change in the View / Linq query.
You're not doing the same thing in the LINQ query as in the SQL. COUNT(result_id) does not count distinct values of result_id - it counts non-null values.
Try this instead:
Count = grp.Select(p => p.result_id).Where(x => x != null).Count()
The point is: you're grouping your data in the LINQ query - and you'll always get at least one group.
That group's Count may be 0 - but the count of groups will be 1.

Resources