【问题标题】:Product with last 4 vendors on transaction date交易日最后 4 家供应商的产品
【发布时间】:2015-03-18 02:48:46
【问题描述】:

你好,我有这个 sql,必须翻译成 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

或者只是为了解释它只是看它的简化版

Select * from master m
outer apply (select top 4 * From Details d where m.Id = d.Id order by someColumns desc)o

我认为我们不能在 nhibernate 中使用子查询作为派生表。如果您有建议,请分享。

谢谢

【问题讨论】:

  • 简而言之,NHibernate FROM 由类/实体映射定义,JOIN 由引用映射定义。所以上面的 SQL 查询是行不通的。这里的解决方案是:1)创建视图 - 并封装所有复杂性 - 将其映射为实体 2)使用原始 SQL 查询来获取这些数据。任何其他解决方案都不适合 ORM
  • 感谢@RadimKöhler 的回复。我已经完成了一个运行良好的存储过程,但由于安全限制,我的老板对 NHibernate 映射实体之外的任何事情都说不。我还试图创建两个单独的查询结果并结合或加入来满足这个要求。有什么想法或建议吗?
  • 我会尝试使用可以映射为实体的视图,或者一些“C#”组合——正如你所说。但关键是,您必须创建的如此复杂的查询完全超出了 ORM 世界的能力......抱歉,没有更好的答案......
  • 再次感谢。至少我可以向我的老板和团队展示这个回复,他们认为在 NHibernate 中一切皆有可能,而且它比 SQL 容易得多。我是这里唯一会写复杂 SQL 的人,这对我来说是个大问题。

标签: nhibernate subquery queryover correlated-subquery


【解决方案1】:

我一直在努力,发现如果想完全使用 QueryOver 可能会非常困难。我想展示我是如何做到这一点的。

首先我带着所有有 StockID 的供应商,稍后加入 StockQuery。

            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();

然后选择仅库存

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>();

这里开始两个循环,用每只股票及其供应商列表中的 5 个顶级供应商填充 List 对象。从查询的 Stockdetail 结果循环和从供应商结果过滤到外循环 stockid 的内部循环,仅在循环中获取前 5 个供应商,完成后仅返回结果报告。它工作正常。

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;
                }

这解决了我的问题,并在调查了很多天后实现了这一点。您可能会找到更好的方法,所以请分享。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 2018-02-22
    • 2011-09-29
    • 2015-01-31
    相关资源
    最近更新 更多