var query = from r in db.Resource
join c in db.ResourceProjectedCapacity on r.ID equals c.ResourceID into ps
from c in ps.DefaultIfEmpty(null)
join p in db.Project on c.ProjectID equals p.ID
select new
{
Capacity = c,
Resource = r,
Project = p
};
I have this linq query but it is only returning resources that have a matching row on ResourceProjectedCapacity table. How can I get all resources and in case they dont have a matching record the Capacity object to be null?
from i in db.Resource
let c = db.ResourceProjectedCapacity.Where(cc => i.id == cc.ResourceID).FirstOrDefault()
let p = db.Project.Where(pp => c.ProjectID == pp.ID).FirstOrDefault()
select new
{
Capacity = C,
Resource = i,
Project = p
}
try above code
I think the secondary inner join messes up the left outer join above it. I think a way to work around it is to break the join into a seperate query, and then left join on that, something like this:
var subquery = from c in db.ResourceProjectedCapacity
join p in db.Project on c.ProjectID equals p.ID
select new { c, p };
var query = from r in db.Resource
join c in subquery on r.ID equals c.c.ResourceID into ps
from c in ps.DefaultIfEmpty(null)
select new
{
Capacity = c.c,
Resource = r,
Project = c.p
};
NB don't worry, it won't do two db queries, it'll only execute against your db once you evaluate query with a .ToList() or something like that.
Related
I have below sql query which I want to convert into LINQ to obtain exactly same results and returned by below query
select *
from (
select distinct DocID
from UserViewDoc
where UserViewDoc.UVID in (102558)) a
left outer join
(
select distinct UserViewDoc.DocID
from UserViewDoc
inner join UserViewHeader on UserViewDoc.UVID = UserViewHeader.UVID
where UserViewDoc.UVID not in (102558)
and UserViewHeader.IsLock = 1) b on a.DocID = b.DocID
where b.DocID is null
)
What I have tried so far is below LINQ statement
var v = (from uvd in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
where IDs.Contains(uvd.UVID)
select new { uvd.DocID, uvd.UVID });
var c = ((from uvd in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
join uvh in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewHeader>() on uvd.UVID equals uvh.UVID
where !IDs.Contains(uvh.UVID) && uvh.IsLock == true
select new { uvd.DocID, uvd.UVID } ));
var d = (from id in v
join ids in c on id.UVID equals ids.UVID into vc
from sub in vc.DefaultIfEmpty()
where sub == null
select id);
The problem I am facing is running the SQL query is returning 30583 records and LINQ version of it is returning all of the 30613 records
I rewrote the query to be exactly like the sql query, i believe that this is the way:
var firstQuery = (from u in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
where IDs.Contains(u.UVID)
select u.DocID).Distinct();
var innerQuery = (from u in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewDoc>()
join uvh in this.ViewSelectorControl.LDReviewContext.GetTable<UserViewHeader>() on uvh.UVID equals u.UVID
where IDs.Contains(u.UIVD) == false
&& uvh.IsLock
select u.DocID).Distinct();
var resultQuery = from f in firstQuery
join i in innerQuery on i equals f into lout
from i in lout.DefaultIfEmpty()
where i == null
select f;
I'm trying to join few tables using LINQ and retrieve a data set. But my problem is when I group the tables, I cannot access the fields of the non grouped tables in the LINQ query. here is my sample code block. Please help
var query = from sb in db.Surfboards
join csb in db.CustomerSurfBoards on sb.SurfBoardID equals csb.SurfBoardID
join c in db.Customers on csb.CustomerID equals c.CustomerID
where c.IsActive
group new { sb,csb} by new {sb.ID, csb.ComponentId} into g
select new ReportModel()
{
ReceivedDate = g.First().Name,
Number = c.First().Number <------- this cannot be accessed
}
what I'm trying to achieve is something like this
select sb.Id, max(c.Number), cbs.Id from Surfboards as sb
inner join CustomerSurfBoards as cbs on sb.SurfBoardID = csb.SurfBoardID
inner join Customers as c on csb.CustomerID = c.CustomerID
group by sb.Id, csb.ComponentId
Try this:
var query = from sb in db.Surfboards
join csb in db.CustomerSurfBoards on sb.SurfBoardID equals csb.SurfBoardID
join c in db.Customers on csb.CustomerID equals c.CustomerID
where c.IsActive
select new {sb.id, c.number, cbs.componentid} into tmp
from t in tmp
group t by new {t.ID, t.ComponentId} into g
select new
{
g.Key.id, g.Key.componentid, number = g.Select(n=>n.number).OrderByDescending().FirstOrDefault()
}
I have this scenario that I didnt find any solution looking through related SO questions :
(from TD as tx
join P as px on tx.field1= px.ID
join Q as rp on tx.field2 = rp.ID
join L as lc on tx.field3= lc.ID
group by tx.field1,
tx.field2,
L.randomfield4,
....a bunch of fields from P,Q,L
)as groupItem
left outer join M on groupItem.field1=M.ID
select new { */ Elements from groupItem and M /*}
My Linq looks as follows :
from tx in TD
join itemP in P on tx.field1 equals P.ID
join itemQ in Q on tx.field2 equals P.ID
join itemL in L on tx.field3 equals P.ID
group new { tx.field1 ,tx.field2 ,L.randomfield4 } by new { **fields from tx,p,q,etc} into groupItem
join dM in M on ????
If i try to select elements from groupItems I cannot access proprieties (because i didnt select anything ).
Can anyone help me with a starting point to this issue ? Also help me with a better name for the question :)
Hopefully I understood your question correctly but here is my answer. I divided the query into two so its easy to understand just combine them together if you fully get into it.
Basically the variable "groupedCollection" is your first joins and your grouping which basically includes the following collections TD, P, Q and L. Then the second variable "finalCollection" is your left outer join which give the result you need.
var groupedCollection = from tx in TD
join itemP in P on tx.field1 equals itemP.ID
join itemQ in Q on tx.field2 equals itemQ.ID
join itemL in L on tx.field3 equals itemL.ID
group new
{
//Select the collections you want to group it by
P,
Q,
L,
TD
}
by new
{
//Select fields you want to output group by here
tx.field1,
tx.field2,
tx.field3,
itemL.RandomField4
}
into g
select new
{
//Use ky to get your properties as they are already grouped by
yourField1 = g.Key.field1,
yourField2 = g.Key.field2,
yourField3 = g.Key.field3,
yourField4 = g.Key.RandomField4
};
var finalCollection = from dM in M
//This is your Left Outer Join
join xx in groupedCollection on dM.ID equals xx.yourField1 into sr
from w in sr.DefaultIfEmpty()
//Until here
select new
{
finalResultID = dM.ID,
finalField1 = w.yourField1,
finalField2 = w.yourField2,
finalField3 = w.yourField3,
finalField4 = w.yourField4
};
for more LINQ stuff this will give you an idea
http://anyrest.wordpress.com/2010/09/27/linq-to-sql-essentials/
my sql statement is
SELECT c.type,c.title,c.datereg, d.ranknum
FROM T_News AS c
INNER JOIN (
SELECT a.id, COUNT(*) AS ranknum
FROM T_News AS a
INNER JOIN T_News AS b
ON (a.type = b.type)
AND (a.datereg >= b.datereg)
GROUP BY a.id
HAVING COUNT(*) <= 3
) AS d ON (c.id = d.id)
ORDER BY c.type, d.ranknum
that i get http://rickosborne.org/blog/2008/01/sql-getting-top-n-rows-for-a-grouped-query/
for Getting TOP N rows for a grouped query
EFUnitOfWork EF = new EFUnitOfWork();
T_NewsRepository News = new T_NewsRepository();
News.UnitOfWork = EF;
var query =
from news1 in News.All()
join news2 in News.All()
on news1.type equals news2.type into resjoin
group news1 by news1.id into idgroup
where idgroup.Count() <= 3
select new { idgroup };
var x = query.ToList();
I did not get any error , but "where idgroup.Count() <= 3" did not work and i get all rows in db as result
Break it down into it's smallest components and then compose the larger query from that. Let's start with the innermost query that makes sense:
SELECT
a.id, COUNT(*) AS ranknum
FROM
T_News AS a
INNER JOIN T_News AS b ON
(a.type = b.type) AND
(a.datereg >= b.datereg)
GROUP BY
a.id
HAVING
COUNT(*) <= 3
I'd convert this to:
// Items with counts/ranknum
var ranknum =
from a in News.All()
join b in News.All() on
a.type equals b.type
where
a.datereg > b.datereg
group by a.id into g
select new { g.Key as id, g.Count() as ranknum };
// Filter the ranknum.
ranknum = ranknum.Where(rn => rn.ranknum <= 3);
Then joining that with the outer query:
SELECT
c.type,c.title,c.datereg, d.ranknum
FROM
T_News AS c
INNER JOIN (<sub-query from above>) as d ON
c.id = d.id
ORDER BY
c.type, d.ranknum
That part becomes simple, as it's just a join between two existing queries.
var query =
from c in News.All()
join rn in ranknum on c.id = rn.id
orderby c.type, rn.ranknum
select new { c.type, c.title, c.datereg, rn.ranknum };
Chances are the SQL that LINQ-to-Entities generates for this is going to look really ugly, and probably be inefficient, in which case, you might want to consider placing this logic in a stored procedure and then calling that through LINQ-to-Entities (which is generally true for more complex queries).
I have the following SQL:
select o.tekst as Enhet,
coalesce(f.Antall,0) as AntallF,
coalesce(f.snitt,0) as SnittF,
coalesce(b.antall,0) as AntallB
from tblhandlingsplan hp
inner join tblorg o on hp.eierorgid = o.orgid
left outer join (select f.handlingsplanid, count(t.tiltakid) as Antall, coalesce(avg(convert(float,t.status)),0) as Snitt from tblhandlingsplanforbedring f left outer join tblhandlingsplantiltak t on f.forbedringsid = t.forbedringsid group by f.handlingsplanid) f on hp.handlingsplanid = f.handlingsplanid
left outer join (select b.handlingsplanid, count(b.bevaringsid) as Antall from tblhandlingsplanbevaring b group by b.handlingsplanid) b on hp.handlingsplanid = b.handlingsplanid
where utsendingsid = 1
Which works exactly how I want it... Now I'm trying to convert this to LINQ...
I have gotten this far
from h in TblHandlingsplans
join o in TblOrgs
on h.EierOrgID equals o.OrgID
join f in TblHandlingsplanForbedrings
on h.HandlingsplanID equals f.HandlingsplanID into f2
join b in TblHandlingsplanBevarings
on h.HandlingsplanID equals b.HandlingsplanID into b2
where h.UtsendingsID == 1
select new {
Enhet = o.Tekst,
AntallF = f2.Count(),
AntallB = b2.Count()
}
however now I'm stuck... I can't for the life of me figure out how to include the average part from the SQL solution... Any takers?
I'm thinking of shoving the whole thing into a SP and leave it with that...
var query1 = from a in DB.Table1
select new
{
Id = a.Id,
Average = a.B.Average()
};
var query2 = from b in DB.Table2
join c in query1 on b.Id equals c.Id
select c;
Just freehanded it, so it might not actually work, but is that the kind of thing you're trying to do? That would result in a single SQL query being created when query2 was used.