我目前正在开发一个c#,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)
所以这引出了两个问题:
编辑:我想要生成的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
答案 0 :(得分:0)
非常感谢安德鲁,他促使我写出了SQL,因此想出了这个。
有一些我不确定的事情:
公司需要两个额外的属性:
public virtual IList<TransactionHeader> TransactionsFromCompany { get; set; }
public virtual IList<TransactionHeader> TransactionsToCompany { get; set; }
需要重写我的自动化,以将这些映射到相应的列:
.Override<Company>(m =>
{
m.HasMany(c => c.TransactionsFromCompany)
.KeyColumn("FromCompany");
m.HasMany(c => c.TransactionsToCompany)
.KeyColumn("ToCompany");
}
现在我可以编写查询:
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();