Nhibernate QueryOver - .SelectCount() with predicate - nhibernate

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)

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
;

Product with last 4 vendors on transaction date

Hi I have this sql and have to translate into NHibernate QueryOver
SELECT S.Number, S.Description, S.BrandDescription, subquery.vendornumber, subquery.vendorname
FROM Stocks.Stock S left join
(select vendorNumber, VendorName, POLID, LastTransactionDate from
(
SELECT top 4 v.Number vendorNumber, v.Name VendorName, PLL.Id POLID, max(por.TransactionDate) as LastTransactionDate,
ROW_NUMBER() OVER(PARTITION BY v.Number ORDER BY max(por.TransactionDate) DESC) AS rk
FROM Purchasing.PurchaseOrderLineItem PLL
inner join Purchasing.PurchaseOrder po on PLL.PurchaseOrderId = po.Id
inner join Purchasing.PurchaseOrderVendor POV on po.Id = POV.PurchaseOrderId
inner join Purchasing.Vendor V on pov.VendorId = v.Id
left outer join Purchasing.PurchaseOrderReceipt POR on PLL.Id = por.PurchaseOrderLineItemId
group by v.Number, v.Name,PLL.Id
order by LastTransactionDate desc
) subquery
where subquery.rk = 1) B on PL.Id = b.POLID
Or just to explain it simply see its simplified version
Select * from master m
outer apply (select top 4 * From Details d where m.Id = d.Id order by someColumns desc)o
I think we cannot use subquery as derived table in nhibernate. If you have suggestions, please share.
Thanks
I was keep working on this and found that it could be very difficult if want to do totally with QueryOver. I want to show how I did this.
First I took all the vendors with StockID to join with StockQuery later.
var stockVendors =
Session.QueryOver<Vendor>(() => V)
.Left.JoinQueryOver(p => V.Stock, () => sstk)
.Where(sstk.Number !=null)
.OrderBy(Projections.Max(() => V.TransactionDate)).Desc()
.ThenBy(() => sstk.Number).Asc()
.ThenBy(() => sv.Number).Asc()
.SelectList(
lst =>
lst.SelectGroup(() => V.Name).WithAlias(() => svhModal.VendorName)
.SelectGroup(() => V.Number).WithAlias(() => svhModal.VendorNumber)
.SelectGroup(() => sstk.Number).WithAlias(() => svhModal.StockNumber)
.Select(Projections.Max(() => V.TransactionDate)).WithAlias(() => svhModal.LastTransactionDate)
)
.TransformUsing(Transformers.AliasToBean()).List();
Then select Stock only
var stockDetail = Session.QueryOver<Stock>(() => stk)
.Where(soneCriteria)
.SelectList(list => list
.Select(() => stk.Id).WithAlias(() => sdrModal.Id)
.Select(() => stk.Number).WithAlias(() => sdrModal.Number)
.TransformUsing(Transformers.AliasToBean<StockDetailReportModal>())
.List<StockDetailReportModal>();
IList<StockVendor> vlst2 = null;
IList<StockDetail> newStock = new List<StockDetail>();
Here starts two loops to fill List object with each stock and its 5 top vendors from vendors list. Loop from Stockdetail result from query and inside loop from vendor result filtered to outer loop stockid, get first 5 vendors only in loop, when done just return the result to report. Its working fine.
foreach (StockDetail ostk in stockDetail)
{
stkid = ostk.Number;
vlst2 = (from v in stockVendors where v.StockNumber == stkid orderby v.LastTransactionDate descending select v).ToList<StockVendor>();
vndrcnt = 0;
stok = new StockDetail
{
Id = ostk.Id,
Number = ostk.Number,
//// other fields too here
};
if (vlst2.Count() == 0)
{
newStock.Add(stok);
}
foreach (StockVendor vn in vlst2)
{
if (vndrcnt == 0)
{
stok.VendorName = vn.VendorName;
stok.VendorNumber = vn.VendorNumber;
// other fields here...
newStock.Add(stok);
}
else
{
newStock.Add(new StockDetail
{
Id = ostk.Id,
Number = ostk.Number,
VendorName = vn.VendorName,
VendorNumber = vn.VendorNumber,
// adding vendor information in stock record.
});
}
vndrcnt++;
if (vndrcnt >= 4)
break;
}
This solved my problem and achieved this after investigating many days. You may find better approach, so please share.

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

Convert SQL to LINQ JOIN/GROUP BY/COUNT/DISTINCT

I got a rather tough query to convert from SQL to LINQ-to-Entities.
Here's my SQL code:
select c_id
from db.c
inner join db.i on c_id = i_c
inner join db.l on c_id = l_c
group by c_id
having count(distinct i_attributeX) > count(distinct l_attributeY)
I seem to have problems with the distinct in linq. Any suggestions?
Cheers
How's this:
var result = db.c
.Where(c =>
c.i.Select(i => i.attributeX).Distinct().Count() >
c.l.Select(l => l.attributeY).Distinct().Count()
)
.Select(c => c.id);
or alternatively
var result = db.c
.Where(c =>
c.i.GroupBy(i => i.attributeX).Count() >
c.l.GroupBy(l => l.attributeY).Count()
)
.Select(c => c.id);

How to convert this SQL query to LINQ or Lambda expression?

I have the following SQL query:
SELECT C.ID, C.Name FROM Category C JOIN Layout L ON C.ID = L.CategoryID
JOIN Position P ON L.PositionID LIKE '%' + CAST(P.ID AS VARCHAR) + '%'
WHERE P.Code = 'TopMenu'
and following data
Position:
ID Code
1 TopMenu
2 BottomMenu
Category
ID Name
1 Home
2 Contact
3 About
Layout
ID CategoryID PositionID
1 1 1
2 2 1,2
3 3 1,2
With the above data, is it possible to convert the SQL query to LINQ or Lambda expression?
Any help is appreciated!
This might do what you want:
Layout
.Where(x => Position
.Where(y => y.Code == "TopMenu")
.Select(y => SqlClient.SqlMethods.Like(x.PositionID, "%" + y.ID.ToString() + "%")
).Count() > 0
).Join(
Category,
x => x.CategoryID,
x => x.ID,
(o,i) => new { ID = i.ID, Name = i.Name }
)
Although you might want to materialize the 'Position' sub query to save on time like so:
var innerSubQuery = Position.Where(y => y.Code == "TopMenu");
Layout
.Where(x => innerSubQuery
.Select(y => SqlClient.SqlMethods.Like(x.PositionID, "%" + y.ID.ToString() + "%")
).Count() > 0
).Join(
Category,
x => x.CategoryID,
x => x.ID,
(o,i) => new { ID = i.ID, Name = i.Name }
);
I do, however, agree with Jon that to really make your life simpler you should change the way you're handling the many-to-many relationship by creating a 'Layout_Position' table.
Well, you won't be able to express the second join as a join, because it's not an equijoin, but this should do it:
from c in category
join l in layout on c.Id equals l.CategoryId
from p in position
where p.Id.Contains(l.PositionId)
select new { c.Id, c.Name };
Note that your "contains/LIKE" clause will give you bad results when you've got more than 9 positions. There are better approaches to many-to-many relations than using a comma-separated list. (Such as an intermediate table.)