LINQ query to select all that don't match - sql

I have the following LINQ query that selects all the pages that have a menu associated with them. I now want to pull out all the pages that don’t have a menu associated with them I.e.. all the pages in Pages that don’t exist in “AssociatedPages”.
var AssociatedPages = (from mm in db.MainMenus
join p in db.Pages on mm.MainMenuPageFK equals p.PageID
select p);
var unAssociatedPages = (from p in db.Pages
where ???
select p);
return View(unAssociatedPages);
I’ve done this before in SQL but I’m not sure on the LINQ syntax.
The setup is one MainMenu can have one too many Pages associated with it
Any help would be greatly appreciated.

Try this:
var unAssociatedPages =
from p in db.Pages
join mm in db.MainMenus on p.PageID equals mm.MainMenuPageFK into mms
where !mms.Any()
select p;
You may find that you need to pop in a couple of .ToArray() calls to improve performance.

Related

Using LinQ with group by more than one column

I'm Newbi in LinQ, I have problem with group by in linQ.
I wan to query like this:
select
MAX(TCheckpointGrouping.Id) AS CheckpointGroupingId,
MAX(TCheckpointGrouping.MCheckpointId) AS CheckpointId,
MAX(MCheckpoint.Name) AS CheckpointName,
MAX(CAST(MCheckpoint.IsMajor AS VARCHAR)) AS IsMajor,
MAX(TCheckpointGrouping.MIndicatorId) AS IndicatorId,
MAX(MIndicator.Name) AS IndicatorName,
MAX(MCriteria.Id) AS CriteriaId,
MAX(MCriteria.Name) AS CriteriaName,
MAX(MPrinciple.Id) AS PrincipleId,
MAX(MPrinciple.Name) AS PrincipleName,
MAX(TCheckpointGrouping.RelationToCheckPoint) AS RelationToCheckPoint
from TCheckpointGrouping
inner join MCheckpoint on MCheckpoint.Id = TCheckpointGrouping.MCheckpointId
inner join MIndicator on MIndicator.Id = TCheckpointGrouping.MIndicatorId
inner join MCriteria on MCriteria.Id = MIndicator.MCriteriaId
inner join MPrinciple on MPrinciple.Id = MCriteria.MPrincipleId
group by
TCheckpointGrouping.MCheckpointId,
TCheckpointGrouping.MIndicatorId
How can i convert query above into LinQ (VB.NET)
thanks
bestRegards
I'm tempted to convert this SQL query to LINQ for you, but I think that would be a waste of opportunity for you to learn yourself.
There's a great page from Microsoft with lot of VB.NET Linq situations: 101 Linq Samples.
You can even find an example of a Group By using Multiple Columns.
Good learning. :)
I am not sure about this, but you can try it. In select part i have not included all the columns.
var result= from TChkgp in TCheckpointGrouping
join MCpoint in MCheckpoint on TChkgp.Id equals MCpoint.Id
join MIndtor in MIndicator on TChkgp.MIndicatorId equals MIndtor.Id
join MCrteia in MCriteria on MIndtor.Id equals MIndtor.MCriteriaId
join MPrncple in MPrinciple on MCrteia.MPrincipleId equals MPrncple.Id
group TChkgp by new (TChkgp.MCheckpointId,TChkgp.MIndicatorId} into g
select new {
CheckpointGroupingId =TChkgp.Id.Max(),
CheckpointId =TChkgp.MCheckpointId.Max,
....
....
};
you can see one simple example on following link
Group and sum in linq

Right Join in Doctrine2 for Symfony2

I have the following working MySQL query:
SELECT *
FROM bogenantworten a
RIGHT JOIN
bogenfragen f ON f.id = a.bogenfragen_id
AND a.personen_id = 3,
BogenTyp t,
BogenFragenGruppe g
WHERE
t.id = f.fragentyp_id AND
g.id = f.fragengruppen_id AND
t.id = 1
ORDER BY f.sortierung ASC
Now I need this in Doctrine2 DQL or QueryBuilder. I already learned that D2 is forcing me to think in objects, but I couldn't find any advice how to tag my entities to make this work.
So I'd like to either have the above MySQL query working in my Symfony2 app or some help how to annotate my entities right so I have a working right join connection between BogenAntworten and BogenFragen (the 3 and the 1 are parameters, just so you know). I already set the OneToMany and ManyToOne annotations for all my entities, but I need something to make a right/left join working.
If you want to help me with my entity design:
I have persons (table Person) who answers (table BogenAntworten) questions (table BogenFragen), and when I show the list of questions I either get the last answer from that question (need UPDATE when saving) or there is none and I have to create it (INSERT when saving). Questions also are in one of many types (table BogenTyp) and are in one of many groups (table BogenFragenGruppe)
Any Ideas?
OK, found it out myself again. The QueryBuilder of Doctrine2 supports a leftJoin (which is identical to the RIGHT JOIN if you switch the two tables). For those need some code, here is the above SQL statement build with QueryBuilder:
$query = $em->createQueryBuilder()
->select(array('f.id', 'f.frage', 'f.sortierung', 'a.antwort', 'g.name'))
->from('MySuperBundle:BogenFragen', 'f')
->leftJoin('f.bogenantworten', 'a', 'WITH', 'a.personen = :pid')
->from('MySuperBundle:BogenTyp', 't')
->from('MySuperBundle:BogenFragenGruppe', 'g')
->where('t.id = :tid')
->andWhere('t.id = f.bogentypen')
->andWhere('g.id = f.bogenfragengruppe')
->orderBy('f.sortierung', 'ASC')
->setParameter('tid', 1)
->setParameter('pid', 3)
->getQuery();
(The parameters are actually dynamic, but for easier reading I used the numbers of the original SQL statement)

LINQ not returning all child records

I have a query in the DB:
SELECT GreenInventoryBlendGradeID,bgx.blendgradeid,
bgX.GreenBlendGradeTypeID,[Description]
FROM [GreenInventory] gi
INNER JOIN [GreenInventoryBlendGradeXref] bgX
ON bgX.[GreenInventoryID] = gi.[GreenInventoryID]
INNER JOIN [BlendGrade] bg
ON bg.[BlendGradeID]=bgx.[BlendGradeID]
That returns 3 records:
TypeID Desc
1 XR
2 XR
1 XF2
The LINQ:
var GreenInventory = (from g in Session.GreenInventory
.Include("GreenInventoryBlendGradeXref")
.Include("GreenInventoryBlendGradeXref.BlendGrade")
.Include("GreenInventoryBlendGradeXref.GreenBlendGradeType")
.Include("GreenInventoryWeightXref")
.Where(x => x.GreenInventoryID == id && x.GreenInventoryBlendGradeXref.Any(bg=>bg.GreenBlendGradeTypeID > 0) )
select g);
I have tried different Where clauses including the simple - (x => x.GreenInventoryID == id)
but always have only the first 2 records returned.
Any Ideas?
If I try the following:
var GreenInventory = (from gi in Session.GreenInventory.Where(y => y.GreenInventoryID == id)
join bgX in Session.GreenInventoryBlendGradeXref.DefaultIfEmpty() on gi.GreenInventoryID equals bgX.GreenInventoryID
join bg in Session.BlendGrade.DefaultIfEmpty() on bgX.BlendGradeID equals g.BlendGradeID
select new { GreenInventory = gi, GreenInventoryBlendGradeXref = bgX, BlendGrade = bg });
I Get back 3 of each objects and the correct information is in the BlendGrade objects. It looks like the 3 GreenInventory objects are the same. They each include 2 of the GreenInventoryBlendGradeXref objects which show the the same 2 records as before.
So I not clear on what the original problem was. Also dont know if this is the best way to resolve it.
Thanks for the answers. If anyone has a further thoughts please let us know.
Based on the few details you present, I would assume that you are missing a join. I have no experience with EntityFramework (I assume that you use this ORM), but as far as I know, the ".Include" tries to ensure that the set of root entities will not change and will not contain duplicates.
Your manually created query seems to indicate that there is at least one 1:n relationship in the model. The result you get from LINQ show that only distinct GreenInventory entities are returned.
Therefore you need to adjust your query and explicitly declare that you want all results (and not only distinct root entities) - I would assume that with an explicit join EntityFramework will yield all expected results - or you need to adjust your mapping.
The first place I'd look in would be your model and joins you have defined between the entities. You might also want to check your generated SQL statement:
Trace.WriteLine(GreenInventory.Provider.ToString())
or use Visual Studio IntelliTrace to investigate what was sent to the database.

How can i do this SQL in Linq? (Left outer join w/ dates)

My LINQ isnt the best, neither is my SQL but im trying to do something like this in LINQ (its kind of in pseudo-code)
select * from CarePlan c
-- only newest Referral based on r.Date (if more than one exists)
left outer join Referral r on r.CarePlanId = c.CarePlanId
where c.PatientId = 'E4A1DA8B-F74D-4417-8AC7-B466E3B3FFD0'
The data looks like this:
A Patient can have a bunch of careplans
each careplan can have 0 to n referrals (I want the newest referral per careplan - if any exist)
Would like to return a list of careplans for each patient (whether or not they have a referral or not, if it has more than one referral - grab the newest one)
Thanks for any help guys
In LINQ you use the DefaultIfEmpty to achieve a left outer join - examples at http://msdn.microsoft.com/en-us/library/bb397895.aspx
Assuming that the referrals are not a (potentially empty) collection on the care plans so you're joining two collections together ...
Your query it would be something like:
Get the latest referral per Care Plan:
var latestReferrals = from r in referrals
group r by r.CarePlanId into lr
select new { CarePlanId = lr.Key, LatestReferral = lr.OrderByDescending(lrd => lrd.Date).First()};
Find the combined details:
var q = from c in CarePlan
where c.PatientId = 'E4A1DA8B-F74D-4417-8AC7-B466E3B3FFD0'
join lr in latestReferrals on c.CarePlanId equals lr.CarePlanId into gj
from subReferral in gj.DefaultIfEmpty()
select new { CarePlanId = c.CarePlanId, LatestReferral = (subReferral == null) ? null : subReferral.LatestReferral };
Depending on whether you want many referral properties or just a few you may or may not want the whole Referral object in the second part or just extract the relevant properties.
You may be able to combine these into a single query but for readability it may be easier to keep them separate. If there is a combined solution you should also compare performance of the two approaches.
EDIT: see comment for joining patients/other tables from care plans
If Patient is joined from Referral (as per comment) then its more complex because you're doing several left outer joins. So switching to the slightly more concise syntax:
var combined = from c in carePlans
where c.PatientId = 'E4A1DA8B-F74D-4417-8AC7-B466E3B3FFD0'
from lr in latestReferral.Where(r => r.CarePlanId == c.CarePlanId).DefaultIfEmpty()
from p in patients.Where(patient => patient.PatientId == ((lr != null) ? lr.LatestReferral.PatientId : -1)).DefaultIfEmpty()
select new { c.CarePlanId, PatientName = (p == null) ? "no patient" : p.PatientName, LatestReferral = (lr == null) ? null : lr.LatestReferral };

Inconsistent results between NHibernate Query and intended results

I have the following query in HQL :
public IEnumerable<Player> PlayersNotInTeam(Team team)
{
return Session.CreateQuery("from Player p where p.Sex = :teamSex and p.Visible and p.Id not in (select pit.Player from PlayerInTeam as pit join pit.Roster as roster join roster.Team as team where team = :teamId)")
.SetParameter("teamId", team.Id)
.SetParameter("teamSex", team.Sex)
.Enumerable<Player>();
}
When I run this query with NHibernate, it will return 2 rows.
If I run the SQL script generated by NH in my database browser (SQLite Explorer):
select player0_.Id as Id26_, player0_.Sex as Sex26_, player0_.FirstName as FirstName26_, player0_.LastName as LastName26_, player0_.DefaultNumber as DefaultN5_26_, player0_.Visible as Visible26_, player0_.DefaultPosition_id as DefaultP7_26_
from Players player0_
where player0_.Sex='Male'
and player0_.Visible=1
and (player0_.Id not in
(select playerinte1_.Player_id
from "PlayerInTeam" playerinte1_
inner join "Roster" roster2_ on playerinte1_.Roster_id=roster2_.Id
inner join Teams team3_ on roster2_.Team_id=team3_.Id,
Players player4_
where playerinte1_.Player_id=player4_.Id
and team3_.Id=2));
I have 3 rows, which is what I should have.
Why are my results different?
Thanks in advance
Mike
I have noticed that sometimes the logged SQL is not exactly the same as the one being really used against the database. The last time I had this issue, it was a problem with trimming the Id value, e.g., where the generated SQL has something like and team3_.Id=2, the SQL being used was actually and team3_.Id='2 ' (or perhaps, player_0.Sex='Male '), which would always fail.
I would suggest you try this HQL:
string hql = #"from Player p where p.Sex = 'Male'
and p.Visible and p.Id not in
(select pit.Player from PlayerInTeam as pit join pit.Roster as roster join roster.Team as team where team = 2)";
return Session.CreateQuery(hql).Enumerable<Player>();
If that works, you need to check if your values have spare whitespaces in them.
I've changed my query like this:
return Session.CreateQuery("from Player p where p.Sex = :teamSex and p.Visible and not exists (from PlayerInTeam pit where pit.Player = p and pit.Roster.Team = :teamId)")
.SetParameter("teamId", team.Id)
.SetParameter("teamSex", team.Sex)
.Enumerable<Player>();
And it now works. I had the idea to use "not exists" after I changed my mappings to try to use LINQ, which gave me the hint.
If you ask why I don't keep LINQ, that's because currently I hide the relationships between my entities as private fields, to force the users of the entities to use the helper functions which associate them. But the wrong thing is that in most cases, that forbids me to use LINQ in my repositories.
But I'm wondering if this wouldn't be better to "un-hide" my relationships and expose them as public properties, but keep my helper functions. This would allow me to use LINQ in my queries.
What do you do in your apps using NH?
Do you think this would be an acceptable trade-off to maintain easy mappings and queries (with the use of LINQ), but with the cost of some potential misuses of the entities if the user doesn't use the helper functions which keep the relationships?