簡體   English   中英

NHibernate QueryOver復雜查詢

[英]NHibernate QueryOver complex query

我目前正在處理ac#,MVC3,NHibernate(在MSSQL 2008上)應用程序。 我將提供一個簡化的示例,因為我認為這是理解這一點的最佳方法。

楷模:

class Stock
{
    public Company Company {get;set;} 
    public Product Product {get;set;} 
    public int quantity {get;set;}  
}   
class TransactionHeader
{
    public Company FromCompany {get;set;}
    public Company ToCompany {get;set;}
    public IList<TransactionRow> Rows {get;set;}
}
class TransactionRows
{
    public Product Product {get;set;}
    public TransactionHeader Header {get;set;}
    public int Quantity {get;set;}
}
class Company
{
    public Country Country {get;set;}
    public State State {get;set;}
    public string Name {get;set;}
}

我的最終目標是產生一個包含以下內容的列表:

產品名稱,公司名稱,國家/地區名稱,州名稱,當前庫存數量,進貨庫存數量,待發貨庫存數量

我可以使用此查詢針對當前庫存執行此操作:

var stockQuery = session.QueryOver<Stock>(() => s)
    .JoinAlias<Company>(() => s.company, () => c, NHibernate.SqlCommand.JoinType.InnerJoin, null)
    .JoinAlias<State>(() => c.State, () => state, NHibernate.SqlCommand.JoinType.InnerJoin, null)
    .JoinAlias<Country>(() => c.Country, () => country, NHibernate.SqlCommand.JoinType.InnerJoin, null)
    .JoinAlias<Product>(() => s.product, () => p, NHibernate.SqlCommand.JoinType.InnerJoin, null);
if (productId.HasValue) { stockQuery = stockQuery.Where(() => p.Id == productId); }
var stock = stockQuery.SelectList(list => list
            .Select(() => s.currentStock).WithAlias(() => rowVM.CurrentStock)
            .Select(() => c.Description).WithAlias(() => rowVM.CompanyName)
            .Select(() => state.Description).WithAlias(() => rowVM.StateName)
            .Select(() => country.Description).WithAlias(() => rowVM.CountryName)
            .Select(() => p.Description).WithAlias(() => rowVM.ProductName))
        .TransformUsing(Transformers.AliasToBean<StockLevelRowVM>())
        .List<StockLevelRowVM>();

我要堅持的是如何基於TransactionHeader / TransactionRow數據添加進來和去庫存的股票。 這是我嘗試查詢來料編號的方法:

            var incommingQuery = session.QueryOver<TransactionRow>(() => itr)
                .JoinAlias<TransactionHeader>(() => itr.TransactionHeader, () => ith, NHibernate.SqlCommand.JoinType.InnerJoin, null)
                .JoinAlias<Company>(() => ith.ToCompany, () => c, NHibernate.SqlCommand.JoinType.InnerJoin, null)
                .JoinAlias<Product>(() => itr.Product, () => p, NHibernate.SqlCommand.JoinType.InnerJoin, null)
                .SelectList(list => list
                    .SelectGroup(() => new { ith.ToCompany, itr.Product })
                    .Select(() => itr.Quantity).WithAlias(() => detail.Quantity)
                    .Select(() => p.Id).WithAlias(() => detail.ProductId)
                    .Select(() => c.Id).WithAlias(() => detail.CompanyId))

按多個屬性分組似乎不起作用:

 Could not determine member from new <>f__AnonymousType3`2(ToCompany = value(<Stuff>).ith.ToCompany, Product = value(<Stuff>).itr.Product)

因此,這引出了兩個問題:

  1. 我要把這件事弄錯了嗎? 存儲過程會更好嗎?
  2. 如果這種方法很好,那么如何按多個字段分組?

編輯:我想生成的那種SQL的示例:

SELECT c.Description CompanyName, 
    p.Description ProductName,
    cc.Description CountryName, 
    cs.Description StateName,
    tmp.CurrentStock, 
    tmp.OutgoingStock, 
    tmp.IncommingStock
FROM
(
    SELECT results.CompanyId, 
        results.ProductId, 
        SUM(results.CurrentStock) CurrentStock, 
        SUM(results.IncommingStock) IncommingStock, 
        SUM(results.OutgoingStock) OutgoingStock
    FROM (
        SELECT 
            c.Id CompanyId,
            p.Id ProductId,
            s.CurrentStock, 
            0 IncommingStock,
            0 OutgoingStock
        FROM Stock s
        INNER JOIN Company c ON c.Id = s.Company
        INNER JOIN [State] cs ON cs.Id = c.[State]
        INNER JOIN Country cc ON cc.Id = cs.Country
        INNER JOIN Product p ON p.Id = s.Product
        WHERE (@CompanyId IS NULL OR c.Id = @CompanyId) AND
            (@CountryId IS NULL OR cc.Id = @CountryId) AND
            (@StateId IS NULL OR cs.Id = @StateId) AND
            (@ProductId IS NULL OR p.Id = @ProductId)
        UNION   
        SELECT 
            c.Id CompanyId,
            p.Id ProductId,
            0 CurrentStock, 
            0 IncommingStock,
            tr.Quantity OutgoingStock
        FROM TransactionRow tr
        INNER JOIN TransactionHeader th ON th.Id = tr.TransactionHeader
        INNER JOIN Company c ON c.Id = th.FromCompany
        INNER JOIN [State] cs ON cs.Id = c.[State]
        INNER JOIN Country cc ON cc.Id = cs.Country
        INNER JOIN Product p ON p.Id = tr.Product
        WHERE (@CompanyId IS NULL OR c.Id = @CompanyId) AND
            (@CountryId IS NULL OR cc.Id = @CountryId) AND
            (@StateId IS NULL OR cs.Id = @StateId) AND
            (@ProductId IS NULL OR p.Id = @ProductId)
        UNION   
        SELECT 
            c.Id CompanyId,
            p.Id ProductId,
            0 CurrentStock, 
            tr.Quantity IncommingStock,
            0 OutgoingStock
        FROM TransactionRow tr
        INNER JOIN TransactionHeader th ON th.Id = tr.TransactionHeader
        INNER JOIN Company c ON c.Id = th.ToCompany
        INNER JOIN [State] cs ON cs.Id = c.[State]
        INNER JOIN Country cc ON cc.Id = cs.Country
        INNER JOIN Product p ON p.Id = tr.Product
        WHERE (@CompanyId IS NULL OR c.Id = @CompanyId) AND
            (@CountryId IS NULL OR cc.Id = @CountryId) AND
            (@StateId IS NULL OR cs.Id = @StateId) AND
            (@ProductId IS NULL OR p.Id = @ProductId)
    ) results
    GROUP BY results.CompanyId, results.ProductId
) tmp
INNER JOIN Company c ON c.Id = tmp.CompanyId
INNER JOIN [State] cs ON cs.Id = c.[State]
INNER JOIN Country cc ON cc.Id = cs.Country
INNER JOIN Product p ON p.Id = tmp.CompanyId

編輯2:所需SQL的第二版

SELECT 
    c.Id CompanyId,
    c.Description CompanyName,
    p.Id ProductId,
    p.Description ProductName,
    cs.Description StateName,
    cc.Description CountryName,
    SUM(s.CurrentStock) CurrentStock, 
    SUM(ttr.Quantity) IncommingStock,
    SUM(ftr.Quantity) OutgoingStock
FROM Stock s
INNER JOIN Company c ON c.Id = s.Company
INNER JOIN [State] cs ON cs.Id = c.[State]
INNER JOIN Country cc ON cc.Id = cs.Country
INNER JOIN Product p ON p.Id = s.Product
LEFT JOIN TransactionHeader fth ON fth.FromCompany = c.Id
LEFT JOIN TransactionRow ftr ON ftr.TransactionHeader = fth.ID 
    AND ftr.Product = p.Id
LEFT JOIN TransactionHeader tth ON tth.ToCompany = c.Id
LEFT JOIN TransactionRow ttr ON ttr.TransactionHeader = tth.ID 
    AND ttr.Product = p.Id
WHERE (@CompanyId IS NULL OR c.Id = @CompanyId) AND
    (@CountryId IS NULL OR cc.Id = @CountryId) AND
    (@StateId IS NULL OR cs.Id = @StateId) AND
    (@ProductId IS NULL OR p.Id = @ProductId)   
GROUP BY p.Id, c.Id, c.Description, p.Description, 
    cs.Description, cc.Description

非常感謝Andrew,他促使我寫出SQL,從而弄清楚了這個SQL。

我缺少一些明智的設置方法:

  1. 公司需要兩個額外的屬性:

     public virtual IList<TransactionHeader> TransactionsFromCompany { get; set; } public virtual IList<TransactionHeader> TransactionsToCompany { get; set; } 
  2. 我的自動映射需要重寫以將它們映射到適當的列:

     .Override<Company>(m => { m.HasMany(c => c.TransactionsFromCompany) .KeyColumn("FromCompany"); m.HasMany(c => c.TransactionsToCompany) .KeyColumn("ToCompany"); } 
  3. 現在我可以編寫查詢:

     StockLevelRowVM rowVM = null; Stock s = null; Company c = null; State state = null; Country country = null; Product p = null; TransactionHeader ith = null; TransactionRow itr = null; TransactionHeader oth = null; TransactionRow otr = null; var stockQuery = session.QueryOver<Stock>(() => s) .JoinAlias<Company>(() => s.company, () => c, NHibernate.SqlCommand.JoinType.InnerJoin, null) .JoinAlias<State>(() => c.State, () => state, NHibernate.SqlCommand.JoinType.InnerJoin, null) .JoinAlias<Country>(() => c.Country, () => country, NHibernate.SqlCommand.JoinType.InnerJoin, null) .JoinAlias<Product>(() => s.product, () => p, NHibernate.SqlCommand.JoinType.InnerJoin, null) .JoinAlias<TransactionHeader>(() => c.TransactionsFromCompany, () => oth, NHibernate.SqlCommand.JoinType.LeftOuterJoin, null) .JoinAlias<TransactionRow>(() => oth.Rows, () => otr, NHibernate.SqlCommand.JoinType.LeftOuterJoin, null) .JoinAlias<TransactionHeader>(() => c.TransactionsToCompany, () => ith, NHibernate.SqlCommand.JoinType.LeftOuterJoin, null) .JoinAlias<TransactionRow>(() => ith.Rows, () => itr, NHibernate.SqlCommand.JoinType.LeftOuterJoin, null); if (productId.HasValue) { stockQuery = stockQuery.Where(() => p.Id == productId); } if (companyId.HasValue) { stockQuery = stockQuery.Where(() => c.Id == companyId); } if (stateId.HasValue) { stockQuery = stockQuery.Where(() => state.Id == stateId); } if (countryId.HasValue) { stockQuery = stockQuery.Where(() => country.Id == countryId); } <call generic paging methods for IQueryOver> result = stockQuery.SelectList(list => list .SelectGroup(() => c.Id) .SelectGroup(() => p.Id) .SelectGroup(() => c.Description).WithAlias(() => rowVM.CompanyName) .SelectGroup(() => state.Description).WithAlias(() => rowVM.StateName) .SelectGroup(() => country.Description).WithAlias(() => rowVM.CountryName) .SelectGroup(() => p.Description).WithAlias(() => rowVM.ProductName) .SelectSum(() => s.currentStock).WithAlias(() => rowVM.CurrentStock) .SelectSum(() => otr.Quantity).WithAlias(() => rowVM.OutgoingStock) .SelectSum(() => itr.Quantity).WithAlias(() => rowVM.IncommingStock)) .TransformUsing(Transformers.AliasToBean<StockLevelRowVM>()) .List<StockLevelRowVM>().ToList(); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM