I have some problem to convert this NHibernate queries into the left join queryover
var query = session.Query<T>.Join(
Session.Query<RecordOrder>(),
q=>q.MiniDbName,
o=>o.DatabaseName,
(q,o)=>new{Record = q, Order = o.OrderValue})
Anyone can help me, I want this query support the left join.
The default join is an inner-join. Each of the additional join types can be specified using the methods .Inner, .Left, .Right, or .Full. For example, to left outer-join on Kittens use:
IQueryOver<Cat,Kitten> catQuery =
session.QueryOver<Cat>()
.Left.JoinQueryOver(c => c.Kittens)
.Where(k => k.Name == "Tiddles");
In your case :
var list =
session.QueryOver<RecordOrder>()
.Left.JoinQueryOver(c => c.Orders).ToList()
Related
How would you convert this trans-sql to LINQ?
I've tried it with the DefaultIfEmpty() but it seems to not be working for me.
Any help is appreciated.
SELECT s.Status
FROM EducationModule M
LEFT JOIN EducationModuleStatus S ON M.CourseID = S.CourseID
AND M.ModuleID = S.ModuleID
AND S.StudentID = '1506'
WHERE M.courseid = 2
Thanks in advance.
Joining on multiple columns in Linq to SQL is a little different.
You have to take advantage of anonymous types and compose a type for the multiple columns you wish to compare against, and under the sheet this will generate the type of join you are looking for.
var abcd = from tl in db.EducationModule
join s in db.EducationModuleStatus
on new { t1.CourseID, t1.ModuleID } equals new {s.CourseID, s.ModuleID}
into tl_s
where tl.CourseID == 2 AND s.StudentID == '1506'
from s in tl_s.DefaultIfEmpty()
select new
{
Status = s.Status
};
I have 2 tables, the left table has data like this:
I do a left join with another table with the following expression:
var result = posicion.Join(fact,
p => p.Cod_articulo,
f => f.Cod_articulo,
(p, f) => new { p.Posicion, p.Cant_historico,
p.Cod_articulo, f.Cantidad_facturada });
The problem is that the results don't include some items from the left table as seen below:
As you can see in the result there is no data for position 3, 6 etc. what would be missing from my join?
You need to do group join (that is left join in Linq). It's better to do with query syntax:
from p in posicion
join f in fact
on p.Cod_articulo equals f.Cod_articulo into g // GroupJoin
from pf in g.DefaultIfEmpty()
select new {
p.Posicion,
p.Cant_historico,
p.Cod_articulo,
Cantidad_facturada = (pf == null) ? null : pf.Cantidad_facturada
}
This query selects all facts corresponding to posicion p into group g. Then from each group we select results, even if there is no corresponding facts for current posicion (that is DefaultIfEmpty case).
Lambda syntax will be much less readable:
posicion.GroupJoin(fact,
p => p.Cod_articulo,
f => f.Cod_articulo,
(p, g) => new { p, g })
.SelectMany(x => x.g.DefaultIfEmpty(), (x, pf) => new {
x.p.Posicion,
x.p.Cant_historico,
x.p.Cod_articulo,
Cantidad_facturada = (pf == null) ? null : pf.Cantidad_facturada
});
Consider also reading this MSDN article: How to: Perform Left Outer Joins
what would be missing from my join?
Presumably there are no entries in fact which have the corresponding Cod_articulo values (e.g. 60155 for posicion 3). Join in LINQ represents an inner join, where there has to be an entry in both sources in order to create an appropriate result.
If you want a left join, you'd typically use GroupJoin, so that each element on the "left" side ends up matching a group of entries from the "right" side, where that group may be empty.
I have a slightly complicated SQL query that I'm trying to convert to LINQ Expression syntax as that is what we use for our code base. Everyone online seems to use query syntax though, which is making finding the right answer quite difficult.
The query is as follows and returns exactly what I'm after (there's probably a nicer way to do this query, please feel free to suggest one);
SELECT e.*, ce.Certificate_ID
FROM FCERTSTest.dbo.Entities AS e
INNER JOIN FCERTSTest.dbo.RequirementEntries AS re
ON re.Position_ID = e.EntityPosition_ID
LEFT JOIN FCERTSTest.dbo.CertificateEntries AS ce
ON ce.Entity_ID = e.EntityID AND ce.Certificate_ID = re.Certificate_ID
WHERE ce.Certificate_ID IS NULL
The problem is converting this. So far all I've got is;
List<Entities> unqualified = new List<Entities>();
unqualified = Entities.Join(RequirementEntries,
ent => ent.EntityPosition_ID,
req => req.Position_ID,
(ent, req) => ent).ToList();
Which I pulled from the Internet...Ihonestly don't understand the query 100% but it gets Entities who's Position has a Requirement, which is what it's meant to do.
So in closing, if someone could help me convert the rest of the SQL statement, it would be much appreciated.
This is how could your original query look in LINQ method syntax:
unqualified = Entities.Join(RequirementEntries,
ent => ent.EntityPosition_ID,
req => req.Position_ID,
(e, r) => new {e,r})
.GroupJoin(CertificateEntries.Where(c=>c.CertificateID == null),
req => new{ Cid = (int?) req.r.Certificate_ID, Eid = (int?) req.e.EntityID },
cer => new{ Cid = (int?) cer.Certificate_ID, Eid = (int?) cer.EntityID },
(x,y) => new {EnRe = x, Cer = y })
.SelectMany(x=> x.Cer.DefaultIfEmpty(),
(x,y) => new { Ent = x.Enre.e, Certs = y});
The GroupJoin is here equivalent of SQL LEFT JOIN.
IMHO, the method syntax is awkward for such complicated joins. The query syntax would be far more readable.
I had tried to join two table conditionally but it is giving me syntax error. I tried to find solution in the net but i cannot find how to do conditional join with condition. The only other alternative is to get the value first from one table and make a query again.
I just want to confirm if there is any other way to do conditional join with linq.
Here is my code, I am trying to find all position that is equal or lower than me. Basically I want to get my peers and subordinates.
from e in entity.M_Employee
join p in entity.M_Position on e.PostionId >= p.PositionId
select p;
You can't do that with a LINQ joins - LINQ only supports equijoins. However, you can do this:
var query = from e in entity.M_Employee
from p in entity.M_Position
where e.PostionId >= p.PositionId
select p;
Or a slightly alternative but equivalent approach:
var query = entity.M_Employee
.SelectMany(e => entity.M_Position
.Where(p => e.PostionId >= p.PositionId));
Following:
from e in entity.M_Employee
from p in entity.M_Position.Where(p => e.PostionId >= p.PositionId)
select p;
will produce exactly the same SQL you are after (INNER JOIN Position P ON E..PostionId >= P.PositionId).
var currentDetails = from c in customers
group c by new { c.Name, c.Authed } into g
where g.Key.Authed == "True"
select g.OrderByDescending(t => t.EffectiveDate).First();
var currentAndUnauthorised = (from c in customers
join cd in currentDetails
on c.Name equals cd.Name
where c.EffectiveDate >= cd.EffectiveDate
select c).OrderBy(o => o.CoverId).ThenBy(o => o.EffectiveDate);
If you have a table of historic detail changes including authorisation status and effective date. The first query finds each customers current details and the second query adds all subsequent unauthorised detail changes in the table.
Hope this is helpful as it took me some time and help to get too.
I'm trying to write some LINQ To SQL code that would generate SQL like
SELECT t.Name, g.Name
FROM Theme t
INNER JOIN (
SELECT TOP 5 * FROM [Group] ORDER BY TotalMembers
) as g ON t.K = g.ThemeK
So far I have
var q = from t in dc.Themes
join g in dc.Groups on t.K equals g.ThemeK into groups
select new {
t.Name, Groups = (from z in groups orderby z.TotalMembers select z.Name )
};
but I need to do a top/take on the ordered groups subquery. According to http://blogs.msdn.com/vbteam/archive/2008/01/08/converting-sql-to-linq-part-7-union-top-subqueries-bill-horst.aspx in VB I could just add TAKE 5 on the end, but I can't get this syntax to work in c#. How do you use the take syntax in c#?
edit: PS adding .Take(5) at the end causes it to run loads of individual queries
edit 2: I made a slight mistake with the intent of the SQL above, but the question still stands. The problem is that if you use extension methods in the query like .Take(5), LinqToSql runs lots of SQL queries instead of a single query.
Second answer, now I've reread the original question.
Are you sure the SQL you've shown is actually correct? It won't give the top 5 groups within each theme - it'll match each theme just against the top 5 groups overall.
In short, I suspect you'll get your original SQL if you use:
var q = from t in dc.Themes
join g in dc.Groups.OrderBy(z => z.TotalMembers).Take(5)
on t.K equals g.ThemeK into groups
select new { t.Name, Groups = groups };
But I don't think that's what you actually want...
Just bracket your query expression and call Take on it:
var q = from t in dc.Themes
join g in dc.Groups on t.K equals g.ThemeK into groups
select new { t.Name, Groups =
(from z in groups orderby z.TotalMembers select z.Name).Take(5) };
In fact, the query expression isn't really making things any simpler for you - you might as well call OrderBy directly:
var q = from t in dc.Themes
join g in dc.Groups on t.K equals g.ThemeK into groups
select new { t.Name, Groups = groups.OrderBy(z => z.TotalMembers).Take(5) };
Here's a faithful translation of the original query. This should not generate repeated roundtrips.
var subquery =
dc.Groups
.OrderBy(g => g.TotalMembers)
.Take(5);
var query =
dc.Themes
.Join(subquery, t => t.K, g => g.ThemeK, (t, g) => new
{
ThemeName = t.Name, GroupName = g.Name
}
);
The roundtrips in the question are caused by the groupjoin (join into). Groups in LINQ have a heirarchical shape. Groups in SQL have a row/column shape (grouped keys + aggregates). In order for LinqToSql to fill its hierarchy from row/column results, it must query the child nodes seperately using the group's keys. It only does this if the children are used outside of an aggregate.