NHibernate Criteria generate invalid SQL for Sybase when using Subqueries - nhibernate

the criteria:
var subQuery = DetachedCriteria.For<RecordInfo>();
.Add(Restrictions.Eq("Property1", "some string"))
.Add(Restrictions.EqProperty("Property2", "record.Id"))
.SetProjection(Projections.Max("Id"));
var criteria = session.CreateCriteria(typeof(Record), "record")
.CreateAlias("record.ListOfRecordInfo", "recordInfo")
.Add(Subqueries.PropertyEq("recordInfo.Id", subQuery));
will generate something like this for Sybase ASE 15.5 dialect:
SELECT this_.Record_Id as Record1_2_3
...
FROM Record this_
INNER JOIN Record_Info Record_Info_
ON this_.Record_Id = Record_Info_.Property_2
WHERE Record_Info_.Record_Info_Id =
(
SELECT max(this_0_.Record_Info_Id) as y0_
FROM Record_Info this_0_
WHERE this_0_.Property_1 = #p0
AND this_0_.Property_2 = this_.Record_Id
)
The problem is the as y0_ that was generated, Sybase doesn't allow alias for sub query for the version of Sybase I'm using.
How do I modify my queries so that NHibernate doesn't generate the alias for the sub query?

We can adjust the projection of the subquery with custom SQL statement. So instead of:
var subQuery = DetachedCriteria.For<RecordInfo>();
...
.SetProjection(Projections.Max("Id")); // instead of this
we can do this:
var subQuery = DetachedCriteria.For<RecordInfo>();
...
.SetProjection(Projections.SqlProjection(" MAX(RecordInfoId) " // use this
, new string[] {"ID"}
, new IType[] {NHibernate.NHibernateUtil.Int32}));
We have to use the column name, because we are skipping the NHibernate Property-to-Column (Id to RecordInfoId).
This will avoid the
SELECT max(this_0_.Record_Info_Id) as y0_ replacing it with
SELECT MAX(RecordInfoId) (our custom SQL)

Related

HQL syntax error : 'NHibernate.Hql.Ast.ANTLR.QuerySyntaxException'

As a beginner in HQL , I have a SQL query that I'm trying to transform into hql.
select * from (
   select *
   from CORRELATION_VUE
   where film = v_oldidfilm and FILM2 not in (
                           select c.idfilm
                           from cotes c
                           where idclient = v_idclient)
   order by CORRELATION desc
 
 )
 where rownum <= 3;
So in HQL I'm trying this :
ISession s = NHibernateHelper.GetCurrentSession();
ITransaction tx = s.BeginTransaction();
IQuery query = s.CreateQuery(
#"select u from (
select u from vueCorreliser u
where u.film = :idfilm
and u.FILM2 not in (
select c.idfilm from cote c
where c.idclient = :idclient)
order by u.CORRELATION desc)
where rownum <= 3; ")
.SetInt32("idfilm", idfilm)
.SetInt32("idclient", idclient);
IList<Film> result = query.List<Film>();
tx.Commit();
return result;
But I'm receiving a syntax error on the CreateQuery line.
What did I do wrong?
Thank you
Though I consider this a duplicate of this other question from you, here is a separate, more explicit answer here.
hql does not support sub-queries in from statement. (It supports them in other statements, such as in where conditions.) You have to rewrite your query without the sub-query in the from.
Your sub-query seems to be there only for limiting rows count. Remove the row limit from the query, and use .SetMaxResults(yourMaxRowCount) on the HQL query object instead.
There are no needs for the termination statement ; in HQL, and I do not know if it is supported. I think it is not, better remove it.
var query = s.CreateQuery(
#"select u from vueCorreliser u
where u.film = :idfilm
and u.FILM2 not in (
select c.idfilm from cote c
where c.idclient = :idclient)
order by u.CORRELATION desc")
.SetInt32("idfilm", idfilm)
.SetInt32("idclient", idclient)
.SetMaxResults(4);
That should fix the QuerySyntaxException.
By the way, your usage pattern of transaction is not safe. When using locally scoped transactions, always nest them in using for ensuring they are properly closed.
using (var tx = session.BeginTransaction())
{
...
tx.Commit();
return result;
}
Even in case of failure, the transaction will then always be disposed, which causes it to rollback if it were still ongoing.

why isn't the where condition passed to oracle in linq to sql?

Consider the following statements. The first one is a LINQ statement, and the second one is old fashioned SQL. They both produce the correct result. The LINQ statement takes 42 seconds because it doesn’t pass the where clause to Oracle. Oracle has to do a complete table scan, then the where clause is satisfied by LINQ after the result. In contrast, the SQL passes the where clause to Oracle, and takes about 3 seconds to run.
Why doesn’t LINQ pass the where clause to Oracle? What can I do about this?
LINQ:
var SamDlvryGrps3 = (from x in _entities.VW_QCRPT_SAMPLE_DLVRY_GRP_SITE
where x.SAMPLEDELIVERYGROUP == EnteredsmplDlvryGrp
select new BatchIdModView
{
BatchId = x.BATCHID,
sampleDeliveryGroup = x.SAMPLEDELIVERYGROUP
}).Distinct().ToList();
SQL:
string sql = "select distinct BatchId, sampleDeliveryGroup from VW_QCRPT_SAMPLE_DLVRY_GRP_SITE where SAMPLEDELIVERYGROUP = :1";
List<BatchIdModView> SamDlvryGrps = _entities.Database.SqlQuery<BatchIdModView>
(sql, new OracleParameter("#smplDlvryGrp", EnteredsmplDlvryGrp.ToUpper())).ToList();

Entity framework join with a subquery via linq syntax

I'm trying to translate a sql query in linq sintax, but I'm having big trouble
This is my query in SQL
select * FROM dbo.ITEM item inner join
(
select SUM([QTA_PRIMARY]) QtaTotale,
TRADE_NUM,
ORDER_NUM,
ITEM_NUM
from [dbo].[LOTTI]
where FLAG_ATTIVO=1
group by [TRADE_NUM],[ORDER_NUM],[ITEM_NUM]
)
TotQtaLottiGroupByToi
on item.TRADE_NUM = TotQtaLottiGroupByToi.TRADE_NUM
and item.ORDER_NUM = TotQtaLottiGroupByToi.ORDER_NUM
and item.ITEM_NUM = TotQtaLottiGroupByToi.ITEM_NUM
where item.PRIMARY_QTA > TotQtaLottiGroupByToi.QtaTotale
and item.FLAG_ATTIVO=1
How can I translate into linq sintax?
This approach doesn't work
var res= from i in context.ITEM
join d in
(
from l in context.LOTTI
group l by new { l.TRADE_NUM, l.ORDER_NUM, l.ITEM_NUM } into g
select new TotQtaByTOI()
{
TradeNum = g.Key.TRADE_NUM,
OrderNum = g.Key.ORDER_NUM,
ItemNum = g.Key.ITEM_NUM,
QtaTotale = g.Sum(oi => oi.QTA_PRIMARY)
}
)
on new { i.TRADE_NUM, i.ORDER_NUM, i.ITEM_NUM} equals new { d.TradeNum, d.OrderNum, d.ItemNum }
I get this error
The type of one of the expressions in the join cluase is incorrect. Type inference failed in the call to 'Join'
Can you help me with this query?
Thank you!
The problem is Anonymous Type comparison. You need to specify matching property names for your two anonymous type's properties (e.g. first, second, third)
I tried it out, here's an example: http://pastebin.com/hRj0CMzs

HQL size using QueryOver without subquery

Hope that someone can answer this.
I know that I can do the following using hql (pseudo code below)
var hql = "from objectA l where size(l.ChildCollection) > 0";
var data = Session.CreateQuery(hql)
.List<objectA>();
Is there a wondering if you could do something similar using QueryOver. Without resorting to using a sub query.I have a session filter on ChildCollection.
Unfortunately,
var query = QueryOver.Of<ObjectA>()
.WhereRestrictionOn(x => x.ChildCollection).IsNotEmpty();
Produces,
WHERE
exists(
select
1
from
[ChildCollection]
where
this_.Id=ObjectA_Id
);
Where as the Hql produces,
where
(
select
count(childcollection1_.ObjectA_Id)
from
[ChildCollection] childcollection1_
where
objectA0_.Id=childcollection1_.ObjectA_Id
and childcollection1_.DTCreated between #p0 and #p1
)>0
Cheers
Tanzy
var query = QueryOver.Of<ObjectA>().WhereRestrictionOn(x => x.ChildCollection).IsNotEmpty();
Both queries will generate similar sql:
SELECT this_.Id
FROM [ObjectA] this_
WHERE exists(select 1 from [ChildObjectB] where this_.Id = [key])
Is this what you were trying to achieve?

HQL / JPQL - Nested select on FROM

I try to convert my SQL query into HQL or JPQL (I want to benefit of the object mapping).
My SQL Request is :
SELECT *
FROM (SELECT bde, MAX(creation_date)
FROM push_campaign GROUP BY bde) temp,
push_campaign pc where pc.bde = temp.bde and pc.creation_date = temp.creation_date;
I try (unsuccessfully) to convert it in JPQL with :
select pc
from (select bde, max(creationDate)
from PushCampaign group by bde) temp,
PushCampaign pc
where pc.bde = temp.bde and pc.creationDate = temp.creationDate
But I got raised :
IllegalArgumentException occured :
org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ( near
line 1, column 16 [select pc from (select id, max(creationDate) from
models.PushCampaign group by bde) temp, models.PushCampaign pc where
pc.id = temp.id]
I read the nested select can only be in select or where clause.
Do you have workarounds to keep the request and benefit of object-mapping ?
Not possible with JPQL or HQL in a single request.
To do this in a single request I propose this :
String campaignToLaunch = "select pc.* from PushCampaign pc ..."
//SQL request which return a resultset compatible with the models.PushCampaign class
Class className = Class.forName("models.PushCampaign");
List<PushCampaign> result = JPA.em()
.createNativeQuery(campaignToLaunch,className)
.getResultList();
this should achive similar results
select pc
from PushCampaign pc
where pc.creationDate =
(select max(creationDate) from PushCampaign inner where inner.bde = pc.bde)
A simple solution could be:
servlet
{
Query q = entityManager.createNativeQuery("SQL");
List<> li = q.getResultList();
#PersistenceContext(unitName="UNIT")
private EntityManager entityManager;
}