QueryOver use Projections.Concat on GroupBy (NHibernate 3.3.5) - nhibernate

I'm trying to implement a bit complicated sql in QueryOver of NHibernate (3.3.5 version) that would be parsed in SQL Server as:
SELECT
CASE WHEN LTR_ReciboCompania IS NULL
THEN CAST(LTR_Id AS VARCHAR(255))
ELSE LTR_ReciboCompania + '#' + LTR_NumPoliza
END
FROM LotesRecibos
GROUP BY
CASE WHEN LTR_ReciboCompania IS NULL
THEN CAST(LTR_Id AS VARCHAR(255))
ELSE LTR_ReciboCompania + '#' + LTR_NumPoliza
END
I've tried a lot of combinations with Projections.Concat() and Projections.SqlFunction("concat", ...) without success.
Sample 1
var concatProjection = Projections.SqlFunction("concat", NHibernateUtil.AnsiString,
Projections.Property<LoteRecibo>(x => x.ReciboCompania), Projections.Constant("#"), Projections.Property<LoteRecibo>(x => x.NumPoliza));
var groupBy = Projections.Conditional(Restrictions.IsNull(Projections.Property<LoteRecibo>(p => p.ReciboCompania)),
Projections.Cast(NHibernateUtil.String, Projections.Property<LoteRecibo>(p => p.Id)),
concatProjection);
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2021)
.Select(Projections.GroupProperty(groupBy))
.List<object[]>();
In that case, the generated query only generates a parameter for the separator in Select but not in Group By:
exec sp_executesql N'SELECT (case when this_.LTR_ReciboCompania is null then cast( this_.LTR_Id as NVARCHAR(255)) else (this_.LTR_ReciboCompania+#p0+this_.LTR_NumPoliza) end) as y0_ FROM LotesRecibos this_ WHERE datepart(year, this_.LTR_FC) = #p1 GROUP BY (case when this_.LTR_ReciboCompania is null then cast( this_.LTR_Id as NVARCHAR(255)) else (this_.LTR_ReciboCompania+?+this_.LTR_NumPoliza) end)',N'#p0 nvarchar(4000),#p1 int',#p0=N'#',#p1=2021
And more readable:
SELECT (
CASE
WHEN this_.LTR_ReciboCompania IS NULL
THEN cast(this_.LTR_Id AS NVARCHAR(255))
ELSE (this_.LTR_ReciboCompania + '#' + this_.LTR_NumPoliza)
END
) AS y0_
FROM LotesRecibos this_
WHERE datepart(year, this_.LTR_FC) = 2021
GROUP BY (
CASE
WHEN this_.LTR_ReciboCompania IS NULL
THEN cast(this_.LTR_Id AS NVARCHAR(255))
ELSE (this_.LTR_ReciboCompania + ? + this_.LTR_NumPoliza)
END
)
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2022)
.SelectList(list => list
.SelectGroup(p => Projections.Concat(p.CodReciboCompania, "#", p.NumPoliza))
)
.List<object[]>();
Sample 2 (simplified without conditional)
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2022)
.SelectList(list => list
.SelectGroup(p => Projections.Concat(p.CodReciboCompania, "#", p.NumPoliza))
)
.List<object[]>();
It throws the following exception:
An unhandled exception of type 'System.Exception' occurred in NHibernate.dll
Unrecognised method call in expression Concat(new [] {p.CodReciboCompania, "#", p.NumPoliza})
But if I set in Select (not in SelectGroup) it works. And I can't understand how to set the Concat function in the group by part of the query.
I should use QueryOver, because we connect to SQL Server and Oracle DB Servers.
UPDATE (Workaround)
While I don't found a better solution, I'll use the first sample without the constant separator. Really I don't need to separate both fields, in my real query I only use the field to group.
var concatProjection = Projections.SqlFunction("concat", NHibernateUtil.AnsiString,
Projections.Property<LoteRecibo>(x => x.ReciboCompania), Projections.Property<LoteRecibo>(x => x.NumPoliza));
var groupBy = Projections.Conditional(Restrictions.IsNull(Projections.Property<LoteRecibo>(p => p.ReciboCompania)),
Projections.Cast(NHibernateUtil.String, Projections.Property<LoteRecibo>(p => p.Id)),
concatProjection);
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2021)
.Select(Projections.GroupProperty(groupBy))
.List<object[]>();

Related

how to use subquery in order by with case in nhibernate?

I need to fetch result from DB table using nhibernate with QueryOver for below sql query. The SQL request is like this:
SELECT Id, Name, Address,phone,ispassed
FROM employee WHERE ispassed = 1
ORDER BY
(CASE WHEN id in (select empId from salary where empId in (2,45,65) and Type=5) THEN 0 ELSE 1 END) asc,
Name desc
I am stuck in Order by. So, please give an example to construct nhibernate query for
ORDER BY
(CASE WHEN id in (select empId from salary where empId in (2,45,65)
and Type=5) THEN 0 ELSE 1 END) asc
I have sub query as :
var subquery = QueryOver.Of<salary>()
.Where(x => x.Type == 5 && x.empId.IsIn(2,65,45))
.SelectList(list => list
.Select(Projections.Distinct(Projections.Property<salary>(x => x.empId))));
and when I am adding subquery in main query as :
query.OrderBy(Projections.Conditional(
Restrictions.In(Projections.SubQuery(subquery)),
Projections.Constant(0),
Projections.Constant(1))).Asc();
It is showing error as "The best overloaded method match for 'NHibernate.Criterion.Projections.SubQuery(NHibernate.Criterion.DetachedCriteria)' has some invalid arguments."
I hope that's what you want:
Employee employeeAlias = null;
var subquery = QueryOver.Of<salary>()
.Where(x => x.Type == 5 && x.empId.IsIn(2,65,45))
.And(x => x.empId == employeeAlias.Id)
.Select(x => x.empId);
var query = session.QueryOver(() => alias)
.Where(x => x.IsPassed)
.OrderBy(Projections.Conditional(
Subqueries.Exists(subquery.DetachedCriteria),
Projections.Constant(0),
Projections.Constant(1))
).Asc
.ThenBy(x => x.Name).Desc
//.Select
//.List
;

Or Constraint for QueryOver

I want to get all PartitionStates by name where it exactly meets the partitionName or starts with it when containing a ..
This is the query I have
return session.QueryOver<PartitionState>()
.Where(p => p.Name == partitionName)
.WhereRestrictionOn(p => p.Name).IsLike(partitionName + ".", MatchMode.Start)
.OrderBy(p => p.StartDate).Desc
.Take(1)
.SingleOrDefault<PartitionState>();
The above query produces an AND expression, but i want it to be an OR.
In SQL it should look like this:
SELECT TOP 1 *
FROM PartitionState
WHERE (Name = #partitionName OR Name like #partitionName+'.%')
ORDER BY StartDate DESC
It seems there is no built in method, but it is possible to pass a restriction into where method.
return session.QueryOver<PartitionState>()
.Where(Restrictions.Or(
Restrictions.Where<PartitionState>(p => p.Name == partitionName),
Restrictions.On<PartitionState>(p => p.Name).IsLike(partitionName + ".", MatchMode.Start)))
.OrderBy(p => p.StartDate)
.Desc.Take(1)
.SingleOrDefault<PartitionState>();

Rails Arel equivalent of this complex sql query

Here is the original logic
(scrape_datas = ScrapeData.find(
:all, :conditions =>
"artist_status = 'NOT_FOUND'
AND blacklisted = 1
AND extracted = 0
and not EXISTS(
SELECT * FROM artist_name_suggestions where original = artist_name
)
I've been able to split up the first part better
scrape_datas = ScrapeData.where(
:artist_status => 'NOT_FOUND',
:blacklisted => 1,
:extracted => 0
)
Although having issues getting the "and not EXISTS" query into the mix
and not EXISTS(
SELECT * FROM artist_name_suggestions where original = artist_name
)
Thanks!
Firstly you can extract simple scopes:
scope :not_found, where(:artist_status => 'NOT_FOUND')
scope :blacklisted, where(:blacklisted => 1)
scope :extracted, where(:extracted => 0)
Then add a query method (assume artist_name is a column of scrape_datas):
def self.no_suggestions
scrape_datas = ScrapeData.arel_table
suggestions = ArtistNameSuggestion.arel_table
where(ArtistNameSuggestion.where(
suggestions[:original].eq(scrape_datas[:artist_name])
).exists.not)
end
Now you can do something like this:
ScrapeData.not_found.blacklisted.extracted.no_suggestions

Nhibernate QueryOver - .SelectCount() with predicate

I need to select count of row with a condition:
Query to collect the full count:
var searchs = searchQuery.SelectList
(list => list
.SelectGroup(order => order.Id).WithAlias(() => groupResult.GlobalId)
.SelectCount(() => _transaction.ReturnStatus).WithAlias(() => groupResult.DeclineCount)
)
I need count of transactions that equals 201. Something like this:
.SelectCount(() => _transaction.ReturnStatus == 201).WithAlias(() => groupResult.DeclineCount) //runtime error
Thanks in advance!
PS:
Original SQL Query:
SELECT TOP 100
globalOrd.ID AS GlobalId ,
SUM(CASE WHEN transact.returnStatus = 201 THEN 1
ELSE 0
END) AS DeclineCount
FROM Orders.Global globalOrd
INNER JOIN Orders.TransactionDetail transactDet ON globalOrd.ID = transactDet.DetailID
INNER JOIN Orders.[Transaction] transact ON transactDet.TransactionID = transact.ID
GROUP BY globalOrd.ID
If you don't need the total count in the same query you can simply add in the restriction before the SelectList:
var searchs = searchQuery.SelectList
(list => list
.Where(() => _transaction.ReturnStatus == 201)
.SelectGroup(order => order.Id).WithAlias(() => groupResult.GlobalId)
.SelectCount(() => _transaction.ReturnStatus).WithAlias(() => groupResult.DeclineCount)
)
If however, you want both the total and the restricted count, you would have to use a SqlProjection for the latter doing something like:
SUM(CASE {alias}.ReturnStatus WHEN 201 THEN 1 ELSE 0 END)

NHibernate QueryOver Restrinctions on a variable

I've a little problem: I would insert a condition into my QueryOver that checks also the variable value. Something like this:
var qOver = QueryOver.Of<MyModel>(() => myMod)
.JoinAlias(() => myMod.SubMod, () => subMod, JoinType.LeftOuterJoin)
.Where(Restrictions.Or(
Restrictions.On(() => myMod.ID).IsIn(MyIDList)
, Restrictions.On(MyIDList == null))
In SQL sintax something like
WHERE #Variable = '' OR MyTable.MyField = #Variable
So, if I my variable is filled I'll filter on my field. If my variable is empty (or null) I'll select every record without filter any content.
How can I reach this result using QueryOver and Restrinctions?
Thank you!
If the variable is null or not set, dont add it to your query.
var qOver = QueryOver.Of<MyModel>(() => myMod)
.JoinAlias(() => myMod.SubMod, () => subMod, JoinType.LeftOuterJoin);
if( MyIDList != null )
qOver = qOver.Where(Restrictions.Or(Restrictions.On(() => myMod.ID).IsIn(MyIDList))