Is it possible in NHibernate to inner join objects during query time with Criteria?
I would like to accomplish something like this:
SELECT p
FROM Person p
INNER JOIN Section s
ON p.sid = s.id
AND p.companyid = s.companyid
The join isn't in the mapping (and can't be there).
Is there something like the following syntax?
var list = session.CreateCriteria(typeof(Person), "p")
.CreateCriteria(typeof(Section), "s")
.Add(Expression.EqProperty("p.SectionId", "s.Id"))
.Add(Expression.EqProperty("p.CompanyId", "s.CompanyId"))
.List();
Is this at all possible? I can't use detachedcriteria here because I have two properties I'm using for joining.
OK, I figured it out, you can use a detachedquery.
I used the following:
var list = session.CreateCriteria(typeof(Person), "p")
.Add(Subqueries.PropertyIn("SectionId", typeof(Section), "s")
.SetProjection(Projections.Property("Id"))
.Add(Expression.EqProperty("s.Id", "p.SectionId"))
.Add(Expression.EqProperty("s.CompanyId", "p.CompanyId"))
)).List();
Which generates an in query which does the same as the inner join.
If you have any "nicer" alternatives, please feel free to share.
Related
I think I'm asking the right question, but let me show you my code before you down-vote my post:
SELECT co_ship.ship_date,
co_ship.co_num,
co.whse,
co_ship.qty_shipped * co_ship.price,
co_ship.price,
co_ship.qty_shipped,
co.cust_num
FROM coitem, co_ship, co
WHERE co.co_num = coitem.co_num AND coitem.co_release = co_ship.co_release AND coitem.co_line = co_ship.co_line AND coitem.co_num = co_ship.co_num
What I am trying to do, is to get rid of the WHERE statement and replace it with a JOIN. (And yes, I realize that my code is probably horribly wrong) Here is what I'm trying:
SELECT co_ship.ship_date,
co_ship.co_num,
co.whse,
co_ship.qty_shipped * co_ship.price,
co_ship.price,
co_ship.qty_shipped,
co.cust_num
FROM coitem, co_ship, co
JOIN co
ON coitem.co_num = co.co_num
JOIN coitem
ON co_ship.co_release=coitem.co_release AND co_ship.coline=coitem.co_line AND co_ship.co_num=co_item.co_num
However, this does not work. I get this error: "The objects "co" and "co" in the FROM clause have the same exposed names. Use correlation names to distinguish them."
I am not entirely sure how to resolve it.
When using the explicit join syntax you don't want more than one item as the source; the rest should appear in the joins (so no from table1, table2, ...)
Your joins should most likely look like this:
FROM coitem
JOIN co_ship
ON coitem.co_release = co_ship.co_release
AND coitem.co_line = co_ship.co_line
AND coitem.co_num = co_ship.co_num
JOIN co ON co.co_num = coitem.co_num
so remove co_ship and co from the from clause.
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
I have a database that contains schemas for skus, kits, kit_contents, and checklists. Here is a query for "Give me all the SKUs defined for kitcontent records defined for kit records defined in checklist 1":
SELECT DISTINCT s.* FROM skus s
JOIN kit_contents kc ON kc.sku_id = s.id
JOIN kits k ON k.id = kc.kit_id
JOIN checklists c ON k.checklist_id = 1;
I'm using Django, and I mostly really like the ORM because I can express that query by:
skus = SKU.objects.filter(kitcontent__kit__checklist_id=1).distinct()
which is such a slick way to navigate all those foreign keys. Django's ORM produces basically the same as the SQL written above. The trouble is that it's not clear to me how to get all the SKUs not defined for checklist 1. In the SQL query above, I'd do this by replacing the "=" with "!=". But Django's models don't have a not equals operator. You're supposed to use the exclude() method, which one might guess would look like this:
skus = SKU.objects.filter().exclude(kitcontent__kit__checklist_id=1).distinct()
but Django produces this query, which isn't the same thing:
SELECT distinct s.* FROM skus s
WHERE NOT ((skus.id IN
(SELECT kc.sku_id FROM kit_contents kc
INNER JOIN kits k ON (kc.kit_id = k.id)
WHERE (k.checklist_id = 1 AND kc.sku_id IS NOT NULL))
AND skus.id IS NOT NULL))
(I've cleaned up the query for easier reading and comparison.)
I'm a beginner to the Django ORM, and I'd like to use it when possible. Is there a way to get what I want here?
EDIT:
karthikr gave an answer that doesn't work for the same reason the original ORM .exclude() solution doesn't work: a SKU can be in kit_contents in kits that exist on both checklist_id=1 and checklist_id=2. Using the by-hand query I opened my post with, using "checklist_id = 1" produces 34 results, using "checklist_id = 2" produces 53 results, and the following query produces 26 results:
SELECT DISTINCT s.* FROM skus s
JOIN kit_contents kc ON kc.sku_id = s.id
JOIN kits k ON k.id = kc.kit_id
JOIN checklists c ON k.checklist_id = 1
JOIN kit_contents kc2 ON kc2.sku_id = s.id
JOIN kits k2 ON k2.id = kc2.kit_id
JOIN checklists c2 ON k2.checklist_id = 2;
I think this is one reason why people don't seem to find the .exclude() solution a reasonable replacement for some kind of not_equals filter -- the latter allows you to say, succinctly, exactly what you mean. Presumably the former could also allow the query to be expressed, but I increasingly despair of such a solution being simple.
You could do this - get all the objects for checklist 1, and exclude it from the complete list.
sku_ids = skus.values_list('pk', flat=True)
non_checklist_1 = SKU.objects.exclude(pk__in=sku_ids).distinct()
I have a question about joins in NHIBERNATE. We had an issue with our sql query that was generated but nhibernate. Our db developer optimized the raw sql so it works as we need, but we need to change the nhibernate code to make generated sql look like optimized.
the part of the original part of the query is:
FROM PERSON_VISIT this_
inner join PERSON_Basic per2_
on this_.PERSON_ID = per2_.PERSON_ID
left outer join PERSONC_QUESTIONS perint10_
on per2_.PERSON_ID = perint10_.PERSON_ID
left outer join TELEPHONE_QUESTIONS intaudit13_
on perint10_.PP_QUESTIONS_ID = intaudit13_.PP_QUESTIONS_ID
inner join C_QUESTIONS intdef14_
on perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and perint10_.QUESTIONS_CODE = intdef14_.QUESTIONS_CODE
and perint10_.QUESTION_ID = intdef14_.QUESTION_ID
The optimized one is :
FROM PERSON_VISIT this_
inner join PERSON_Basic per2_
on this_.PERSON_ID = per2_.PERSON_ID
left outer join PERSONC_QUESTIONS perint10_
on per2_.PERSON_ID = perint10_.PERSON_ID
left outer join TELEPHONE_QUESTIONS intaudit13_
on perint10_.PP_QUESTIONS_ID = intaudit13_.PP_QUESTIONS_ID
left outer join C_QUESTIONS intdef14_
on perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and perint10_.QUESTIONS_CODE = intdef14_.QUESTIONS_CODE
and perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
To change query from inner join to left outer join is easy, i changed only one line of code:
.CreateAlias("PersonInt.QuestionEntity", "IntDef", JoinType.LeftOuterJoin)
But how I can add
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
using nhibernate code?
There is an option to add reference from PERSON_VISIT definition to C_QUESTIONS, but the problem is that
PERSON_VISIT is used everywhere and I don't want this change to possibly break other queries, I just wnat to add only one line of code to add, how I can do that? Is there any way to have access to the raw join to change it? Or some other way to add this
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
To the query?
I know that somebody will say that we can add a restriction to the query through criteria.Add, but it is not an option cause db developer optimized our query taking this restriction from WHERE clause to the join.
How I can do that quickly without changing the models definitions? Just changing only this one query without changing the whole model?
It is possible using HQL and the Criteria API's.
This question gives you the answer: Adding conditionals to outer joins with nhibernate
Something like this may solve your issue.
.CreateAlias("PersonInt.QuestionEntity", "IntDef", JoinType.LeftOuterJoin,
Restrictions.EqProperty("DISCIPLINE_CODE", "IntDef.DISCIPLINE_CODE"))
Thanks for answers. We use 2.0 version of NHibernate in our project so we didn't have a chance to use new methods of .CreateAlias with restrictions.
I have fixed an issue using Interceptors:
public class SqlInterceptor : EmptyInterceptor, IInterceptor
{
SqlString IInterceptor.OnPrepareStatement(SqlString sql)
{
//manipulating with the sql
return sql;
}
}
than
var factory = Session.SessionFactory;
var session = factory.OpenSession(new SqlInterceptor());
And use my query without a change.
Is it possible to do this in NHibernate without using CreateSQLQuery. Preferably with Linq To Nhibernate. The biggest question is how do I do joins not on a primary key?
SELECT DISTINCT calEvent.* From CalendarEvent as calEvent
LEFT JOIN UserChannelInteraction as channelInteraction on channelInteraction.ChannelToFollow_id = calEvent.Channel_id
LEFT JOIN UserCalendarEventInteraction as eventInteraction on eventInteraction.CalendarEvent_id = calEvent.Id
LEFT JOIN UserChannelInteraction as eventInteractionEvent on eventInteractionEvent.UserToFollow_id = eventInteraction.User_id
WHERE (calEvent.Channel_id = #intMainChannelID
OR channelInteraction.User_id = #intUserID
OR eventInteraction.User_id = #intUserID
OR (eventInteractionEvent.User_id = #intUserID AND eventInteraction.Status = 'Accepted'))
AND calEvent.StartDateTime >= #dtStartDate
AND calEvent.StartDateTime <= #dtEndDate
ORDER BY calEvent.StartDateTime asc
Hmmm... maybe you need to try to leverage subqueries?
Check this out: http://devlicio.us/blogs/derik_whittaker/archive/2009/04/06/simple-example-of-using-a-subquery-in-nhibernate-when-using-icriteria.aspx
You can do arbitrary joins by using Theta joins. A theta join is the Cartesian product, so it results in all possible combinations, which then can be filtered.
In NHibernate you can perform a theta style join like this (HQL):
from Book b, Review r where b.Isbn = r.Isbn
You can then add any filtering conditions you want to, order the results and everything else you might want to do.
from Book b, Review r where b.Isbn = r.Isbn where b.Title = 'My Title' or r.Name = 'John Doe' order by b.Author asc
Here is an article about theta joins in Hibernate (not NHibernate, but it's still relevant).
However, since the theta join is a Cartesian product, you might want to think twice and do some performance testing before you use that approach to do a three-join query.