Converting HQL Query to Criteria generates invalid SQL - nhibernate

I am attempting to convert the following HQL query to Criteria.
from SubportfolioAudit as a
where a.ID in (select max(a2.ID)
from SubportfolioAudit as a2
where a2.EffectiveDate = :EffectiveDate
and a.Subportfolio.ID = a2.Subportfolio.ID
group by a2.Subportfolio.ID)
and a.Subportfolio.ID in (:SubportfolioList)
So far I have the following:
var crit = Session.CreateCriteria(typeof(SubportfolioAudit));
var currentAuditByEffectiveDate = DetachedCriteria.For(typeof(SubportfolioAudit))
.SetProjection(Projections.ProjectionList()
.Add(Projections.Max("ID"))
.Add(Projections.GroupProperty("Subportfolio.ID")))
.Add(Expression.Eq("EffectiveDate", effectiveDate));
crit.Add(Subqueries.PropertyIn("ID", currentAuditByEffectiveDate));
crit.Add(Expression.In("Subportfolio.ID", subportfolioList.Select(x => x.ID).ToArray()));
return crit.List<SubportfolioAudit>();
Which generates an invalid sub query, you can see it here:
SELECT this_.SubportfolioAuditId as Subportf1_21_6_,
this_.Event as Event21_6_,
this_.CreatedDate as CreatedD3_21_6_,
this_.[User] as User4_21_6_,
this_.EffectiveDate as Effectiv5_21_6_,
this_.SubportfolioId as Subportf6_21_6_,
subportfol2_.SubportfolioId as Subportf1_12_0_,
subportfol2_.PACERCode as PACERCode12_0_,
subportfol2_.HedgeRatio as HedgeRatio12_0_,
subportfol2_.Name as Name12_0_,
subportfol2_.Strategy as Strategy12_0_,
subportfol2_.BasketId as BasketId12_0_,
subportfol2_.PortfolioId as Portfoli7_12_0_,
subportfol2_.ReferenceBasketId as Referenc8_12_0_,
(SELECT CASE
WHEN Count(* ) > 0
THEN 1
ELSE 0
END
FROM Asset
WHERE Asset.SubportfolioId = subportfol2_.SubportfolioId) as formula1_0_,
basket3_.BasketId as BasketId7_1_,
basket3_.Name as Name7_1_,
basket3_.CatsBenchmarkCode as CatsBenc4_7_1_,
basket3_.Description as Descript5_7_1_,
basket3_.BaseBasketId as BaseBask6_7_1_,
basket3_.Filename as Filename7_1_,
basket3_.Type as Type7_1_,
basket4_.BasketId as BasketId7_2_,
basket4_.Name as Name7_2_,
basket4_.CatsBenchmarkCode as CatsBenc4_7_2_,
basket4_.Description as Descript5_7_2_,
basket4_.BaseBasketId as BaseBask6_7_2_,
basket4_.Filename as Filename7_2_,
basket4_.Type as Type7_2_,
portfolio5_.PortfolioId as Portfoli1_5_3_,
portfolio5_.BaseCurrencyCode as BaseCurr2_5_3_,
portfolio5_.TradingAccountNumber as TradingA3_5_3_,
portfolio5_.Name as Name5_3_,
portfolio5_.ClientId as ClientId5_3_,
client6_.ClientId as ClientId4_4_,
client6_.ExplicitFee as Explicit2_4_4_,
client6_.Affiliated as Affiliated4_4_,
client6_.ClientGroup as ClientGr4_4_4_,
client6_.RCODA as RCODA4_4_,
client6_.Name as Name4_4_,
client6_.BaseCurrencyCode as BaseCurr7_4_4_,
client6_.Region as Region4_4_,
basket7_.BasketId as BasketId7_5_,
basket7_.Name as Name7_5_,
basket7_.CatsBenchmarkCode as CatsBenc4_7_5_,
basket7_.Description as Descript5_7_5_,
basket7_.BaseBasketId as BaseBask6_7_5_,
basket7_.Filename as Filename7_5_,
basket7_.Type as Type7_5_
FROM dbo.SubportfolioAudit this_
inner join dbo.Subportfolio subportfol2_
on this_.SubportfolioId = subportfol2_.SubportfolioId
left outer join dbo.Basket basket3_
on subportfol2_.BasketId = basket3_.BasketId
left outer join dbo.Basket basket4_
on basket3_.BaseBasketId = basket4_.BasketId
left outer join dbo.Portfolio portfolio5_
on subportfol2_.PortfolioId = portfolio5_.PortfolioId
left outer join dbo.Client client6_
on portfolio5_.ClientId = client6_.ClientId
left outer join dbo.Basket basket7_
on subportfol2_.ReferenceBasketId = basket7_.BasketId
WHERE this_.SubportfolioAuditId in (SELECT max(this_0_.SubportfolioAuditId) as y0_,
this_0_.SubportfolioId as y1_
FROM dbo.SubportfolioAudit this_0_
WHERE this_0_.EffectiveDate = '2009-09-11T00:00:00.00' /* #p0 */
GROUP BY this_0_.SubportfolioId)
and this_.SubportfolioId in (13 /* #p1 */,14 /* #p2 */,15 /* #p3 */,16 /* #p4 */,
17 /* #p5 */,18 /* #p6 */,19 /* #p7 */,20 /* #p8 */,
21 /* #p9 */)
I know that the Projections.GroupProperty() is causing the problem, but I cannot seem to find another way to accomplish what I want.

I believe (and correct me if I am wrong) that the sub query is invalid because you are missing the second where clause you have set in your HQL (... and a.Subportfolio.ID = a2.Subportfolio.ID).
Converting your Criteria query as below I believe (cannot verify as I cannot test your code) that it will do the trick.
var crit = Session.CreateCriteria(typeof(SubportfolioAudit), "mainQuery");
var currentAuditByEffectiveDate = DetachedCriteria.For(typeof(SubportfolioAudit),"subQuery")
.SetProjection(Projections.ProjectionList()
.Add(Projections.Max("ID"))
.Add(Projections.GroupProperty("Subportfolio.ID")))
.Add(Expression.Eq("EffectiveDate", effectiveDate));
.Add(Expression.EqProperty("subQuery.ID", "mainQuery.ID"));
crit.Add(Subqueries.PropertyIn("mainQuery.ID", currentAuditByEffectiveDate));
crit.Add(Expression.In("mainQuery.Subportfolio.ID", subportfolioList.Select(x => x.ID).ToArray()));
return crit.List<SubportfolioAudit>();
What I have done is to add an extra where clause in the DetachedCriteria that 'connects' the SubportfoliAudit.ID column of the subquery with the outer main query. I have also provided aliases to name the queries.

Related

I need to transform a SQL query with inner joins to Linq in Entity Framework

I am very new to translating queries to entity, I don't know how to replace that query into linq in my code
select
brules.rule_description, brules.user_story_number,
so.source_name,
count(dlog.row_id) as error_count,
cast(execution_date as date) as execution_date
from
br.lk_business_rules brules
inner join
br.business_rules_detailed_log dlog on dlog.user_story_number = brules.user_story_number
inner join
br.lk_business_rules_source so on so.source_id = source_id_fk
where
brules.status_id_fk = 3
group by
brules.rule_description, brules.user_story_number,
so.source_name, cast(execution_date as date)
order by
brules.rule_description
i tried this:
var query = from br in _context.Lk_business_rules
join detLog in _context.Business_rules_detailed_log
on br.User_story_number equals detLog.User_story_number
join source in _context.Lk_business_rules_source
on detLog.Source_id equals source.Source_id
where br.Status_id_fk == 3
select new
{
Business_rule_description = br.Rule_description,
Business_rule_storynumber = br.User_story_number,
Source = source.Source_name,
Error_count = detLog.Row_id.Count,
Date = detLog.Execution_date
};
but not succed

Left outter join linq

How do i change the training events into a left outer join in training events im very basic at linq so excuse my ignorance its not retrieve records that don't have any trainnevent reference attached to it
var q = from need in pamsEntities.EmployeeLearningNeeds
join Employee e in pamsEntities.Employees on need.EmployeeId equals e.emp_no
join tevent in pamsEntities.TrainingEvents on need.TrainingEventId equals tevent.RecordId
where need.EmployeeId == employeeId
where need.TargetDate >= startdate
where need.TargetDate <= enddate
orderby need.TargetDat
It's best to use where in combination with DefaultIfEmpty.
See here: LEFT JOIN in LINQ to entities?
var query2 = (
from users in Repo.T_Benutzer
from mappings in Repo.T_Benutzer_Benutzergruppen.Where(mapping => mapping.BEBG_BE == users.BE_ID).DefaultIfEmpty()
from groups in Repo.T_Benutzergruppen.Where(gruppe => gruppe.ID == mappings.BEBG_BG).DefaultIfEmpty()
//where users.BE_Name.Contains(keyword)
// //|| mappings.BEBG_BE.Equals(666)
//|| mappings.BEBG_BE == 666
//|| groups.Name.Contains(keyword)
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
Which is equivalent to this select statement:
SELECT
T_Benutzer.BE_User
,T_Benutzer_Benutzergruppen.BEBG_BE
-- etc.
FROM T_Benutzer
LEFT JOIN T_Benutzer_Benutzergruppen
ON T_Benutzer_Benutzergruppen.BEBG_BE = T_Benutzer.BE_ID
LEFT JOIN T_Benutzergruppen
ON T_Benutzergruppen.ID = T_Benutzer_Benutzergruppen.BEBG_BG

nhibernate using icriteria with a group by and having, and getting total row count (c#)

So I have an nhibernate icriteria query that gets the list of results that I want.
However I cannot figure out how to get the total row count.
public IEnumerable<SpecialismCombo> List(SpecialismListCriteria criteria, out int total)
{
//run the sub query
ICriteria countAgencies = m_SpecialismComboRepository.QueryAlias("sc");
if (!String.IsNullOrEmpty(criteria.AgencyIds) && !criteria.AgencyIds.Equals("0"))
{
List<int> AgencyIds = criteria.AgencyIds.Split(new char[] { ',' }).ToList<int>();
countAgencies.CreateAlias("Agencies", "a", NHibernate.SqlCommand.JoinType.InnerJoin);
countAgencies.Add(Restrictions.In("a.AgencyId", AgencyIds));
}
total = Convert.ToInt32(
countAgencies.SetProjection(
Projections.CountDistinct("a.AgencyId")
).UniqueResult()
);
//create query
ICriteria query = m_SpecialismComboRepository.QueryAlias("sc");
if (!String.IsNullOrEmpty(criteria.AgencyIds) && !criteria.AgencyIds.Equals("0"))
{
List<int> AgencyIds = criteria.AgencyIds.Split(new char[] { ',' }).ToList<int>();
query.CreateAlias("Agencies", "a", NHibernate.SqlCommand.JoinType.InnerJoin);
query.Add(Restrictions.In("a.AgencyId", AgencyIds));
}
query.Add(Restrictions.Eq(Projections.Count("SpecialismComboId"),total));
ProjectionList pl = Projections.ProjectionList()
.AddPropertyAlias("SpecialismComboId", "SpecialismComboId")
.AddPropertyAlias("SpecialismComboDisplayText", "SpecialismComboDisplayText")
.AddPropertyAlias("SpecialismComboDisciplineDisplayText", "SpecialismComboDisciplineDisplayText")
.AddPropertyAlias("SpecialismComboIdText", "SpecialismComboIdText")
.Add(Projections.GroupProperty("SpecialismComboId"));
// set the right total for records being returned
total = query.ToRowCount();
// Return the query results
return query
.SetProjection(Projections.Distinct(
pl
))
.SetResultTransformer(new KnownPropertyAliasToBeanResultTransformer(typeof(SpecialismCombo)))
.SetFirstResult(criteria.FirstRecord)
.SetMaxResults(criteria.PageSize)
.List<SpecialismCombo>() as List<SpecialismCombo>;
}
I was trying to use an ICriteriaExtension we have:
public static int ToRowCount(this ICriteria query)
{
return query.ToRowCountQuery().UniqueResult<int>();
}
But it returns null.
so the query generated in SQL is:
exec sp_executesql N'SELECT distinct top 15 this_.SpecialismComboId as y0_,
(select dbo.fn_GetSpecialismComboDisplayText(this_.SpecialismComboId,''/'')) as y1_,
(select dbo.fn_GetSpecialismComboDisciplineDisplayText(this_.SpecialismComboId,'', '')) as y2_,
(select dbo.fn_GetSpecialismComboIdText(this_.SpecialismComboId,''|'')) as y3_,
this_.SpecialismComboId as y4_
FROM dbo.SpecialismCombo this_
inner join AgencySpecialismCombo agencies3_ on this_.SpecialismComboId=agencies3_.SpecialismComboId
inner join dbo.Agency a1_ on agencies3_.AgencyId=a1_.AgencyId WHERE a1_.AgencyId in (#p0)
GROUP BY this_.SpecialismComboId HAVING count(this_.SpecialismComboId) = #p1',N'#p0 int,#p1 int',#p0=4741,#p1=1
The Row Count based on my above code is
exec sp_executesql N'SELECT top 2147483647 count(*) as y0_
FROM dbo.SpecialismCombo this_
inner join AgencySpecialismCombo agencies3_ on this_.SpecialismComboId=agencies3_.SpecialismComboId
inner join dbo.Agency a1_ on agencies3_.AgencyId=a1_.AgencyId WHERE a1_.AgencyId in (#p0)
HAVING count(this_.SpecialismComboId) = #p1',N'#p0 int,#p1 int',#p0=4741,#p1=1
But what I need it to be like is this:
exec sp_executesql N'SELECT sum(idcount) from
(select count(*) idcount
FROM dbo.SpecialismCombo this_
inner join AgencySpecialismCombo agencies3_ on this_.SpecialismComboId=agencies3_.SpecialismComboId
inner join dbo.Agency a1_ on agencies3_.AgencyId=a1_.AgencyId WHERE a1_.AgencyId in (#p0)
GROUP BY this_.SpecialismComboId HAVING count(this_.SpecialismComboId) = #p1) as sub
',N'#p0 int,#p1 int',#p0=4741,#p1=1
But once again I can't figure out how to use icriteria (which is what our data access standard is) to get this query and the correct count being returned!!
Any ideas would be appreciated :)
Using fluent nhibernate 2.0 I believe.
Thanks!!
AFAIK in ICriteria you can't specify subqueries in the FROM clause.
Either return the subcounts and sum clientside or resort to HQL or SQL.
The answer a colleague of mine came up with:
public IEnumerable<SpecialismCombo> List(SpecialismListCriteria criteria, out int total)
{
//create query
DetachedCriteria query = DetachedCriteria.For<SpecialismCombo>("sc");
if (!String.IsNullOrEmpty(criteria.AgencyIds) && !criteria.AgencyIds.Equals("0"))
{
List<int> agencyIds = criteria.AgencyIds.Split(new char[] { ',' }).ToList<int>();
query.CreateAlias("Agencies", "a", NHibernate.SqlCommand.JoinType.InnerJoin);
query.Add(Restrictions.In("a.AgencyId", agencyIds));
// Subquery
var subqueryCount = query
.SetProjection(Projections.CountDistinct("a.AgencyId"))
.GetExecutableCriteria(NHibernateSessionManager.Instance.GetSession())
.UniqueResult<int>();
query.Add(Restrictions.Eq(Projections.Count("SpecialismComboId"), subqueryCount));
}
ProjectionList pl = Projections.ProjectionList()
.AddPropertyAlias("SpecialismComboId", "SpecialismComboId")
.AddPropertyAlias("SpecialismComboDisplayText", "SpecialismComboDisplayText")
.AddPropertyAlias("SpecialismComboDisciplineDisplayText", "SpecialismComboDisciplineDisplayText")
.AddPropertyAlias("SpecialismComboIdText", "SpecialismComboIdText")
.Add(Projections.GroupProperty("SpecialismComboId"));
total = FullCountQuery(query)
.GetExecutableCriteria(NHibernateSessionManager.Instance.GetSession())
.ToRowCount();
// Return the query results
return query
.SetProjection(Projections.Distinct(pl))
.SetResultTransformer(new KnownPropertyAliasToBeanResultTransformer(typeof(SpecialismCombo)))
.SetFirstResult(criteria.FirstRecord)
.SetMaxResults(criteria.PageSize)
.GetExecutableCriteria(NHibernateSessionManager.Instance.GetSession())
.List<SpecialismCombo>() as List<SpecialismCombo>;
}
private DetachedCriteria FullCountQuery(DetachedCriteria query)
{
ProjectionList pl = Projections.ProjectionList()
.Add(Projections.GroupProperty("SpecialismComboId"));
var subquery = CriteriaTransformer.Clone(query).SetProjection(Projections.Distinct(pl));
return DetachedCriteria.For<SpecialismCombo>("sc")
.Add(Subqueries.PropertyIn("sc.SpecialismComboId", subquery))
.SetProjection(Projections.CountDistinct("SpecialismComboId"));
}
I thought I was getting the hang of icriteria and projections and stuff. But this fullcountquery blew that away :)

NHibernate how to create sql:on ID=s.PID AND p.Name = 'ABC'

[NUnit.Framework.Test]
public void Test2()
{
NHibernate.ISession session = Z.Core.NHibernateCore.NHibernateHelper.GetCurrentSession();
var crit = session.CreateCriteria("_School");
crit.CreateCriteria("_ListStudent", "__ListStudent", NHibernate.SqlCommand.JoinType.LeftOuterJoin);
crit.Add(NHibernate.Criterion.Expression.Eq("__ListStudent.Name", "Abc"));
var list = crit.List();
Console.Write(list.Count);
}
NHibernate:
SELECT * FROM Tst_School this_ left outer join Tst_Student liststud1_ on this_.Guid=liststud1_.Guid WHERE liststud1_.Name = 'Abc'
How to create sql:
SELECT * FROM Tst_School this_ left outer join Tst_Student liststud1_ on this_.Guid=liststud1_.Guid AND liststud1_.Name = 'Abc'
Thanks
You should check WITH clause in HQL. I don't know if it's possible in CriteriaQuery.
http://nhforge.org/blogs/nhibernate/archive/2009/05/17/nhibernate-2-1-0-hql-with-clause.aspx

LINQ to SQL - How to add a where clause to a left join?

This LINQ query expression emits a left join and works:
from p in Prices
join ip in ItemPrices
on new { p.PriceId, ItemId = 7 } equals
new { ip.PriceId, ip.ItemId }
into priceItemPrice
from pip in priceItemPrice.DefaultIfEmpty()
select new
{
pricesPriceId = p.PriceId,
z = (int?)pip.PriceId,
p.Content,
p.PriceMinQ
}
SQL emitted:
-- Region Parameters
DECLARE #p0 Int = 7
-- EndRegion
SELECT [t0].[priceId] AS [pricesPriceId],
[t1].[priceId] AS [z],
[t0].[price] AS [Content],
[t0].[priceMinQ] AS [PriceMinQ]
FROM [price] AS [t0]
LEFT OUTER JOIN [itemPrice] AS [t1]
ON ([t0].[priceId] = [t1].[priceId])
AND (#p0 = [t1].[itemId])
How can I get it to emit the SQL below? It just has the where clause tacked on the end. A where clause is not accepted under the "from pip" and a where lambda expression before DefaultIfEmpty() doesn't work. I know I can filter it out in the select, but that's not what I need.
SELECT [t0].[priceId] AS [pricesPriceId],
[t1].[priceId] AS [z],
[t0].[price] AS [Content],
[t0].[priceMinQ] AS [PriceMinQ]
FROM [price] AS [t0]
LEFT OUTER JOIN [itemPrice] AS [t1]
ON ([t0].[priceId] = [t1].[priceId])
AND (#p0 = [t1].[itemId])
WHERE [t1].[priceId] is null
Update
Oy vey, my mistake, the where clause did work - for some reason VS2008 was not behaving and giving me grief and my stomach was growling. I tested back in LinqPad and the where clause was fine. So this little addition did work:
...
from pip in priceItemPrice.DefaultIfEmpty()
*** where pip.ItemId == null ***
select new
...
Here is a sample of how OneDotNetWay has done something similar. I've tried to take their example and match up your query.
var query = p in Prices
join ip in ItemPrices
on
new { p.PriceId, ItemId = 7 }
equals
new { ip.PriceId, ip.ItemId }
into priceItemPrice
from pip in priceItemPrice.DefaultIfEmpty()
select new
{
pricesPriceId = p.PriceId,
z = (int?)pip.PriceId,
p.Content,
p.PriceMinQ
}