【问题标题】:How to add List to a Key in a Linq to Sql Group By如何将列表添加到 Linq to Sql Group By 中的键
【发布时间】:2017-02-17 16:02:05
【问题描述】:

我想检索一个元素列表作为 group by 的复合键的一部分。但到目前为止,我一直无法编写查询来执行此操作。

我们正在显示每种 RawMaterial 的总库存(以下是模型的更多详细信息),我们希望与每种 RawMaterial 的供应商一起列出。 我试过这个查询:

var list = this.Stocks.Where(x => x.StockType == StockTypeEnum.RawMaterialEntered)
.GroupBy(i => new { RawMaterialId = i.RawMaterial.Id, RawMaterial = i.RawMaterial.Name, 
                    Suppliers = i.RawMaterial.Suppliers.Select(j=> new { Id= j.Supplier.Id, Name = j.Supplier.Name}) })
.Select(g => new StockSummary
{
   TotalAmount = g.Sum(i => i.Amount),
   ComponentId = g.Key.RawMaterialId,                   
   Component = g.Key.RawMaterial,
   Suppliers = g.Key.Suppliers.Select(h=> new StockItemModel(){ Id = h.Id, Name = h.Name} ).ToList()
})
.OrderByDescending(g => g.Component).ToList();

它可以构建,但是当我尝试运行它时,我得到了这个异常:

“System.NotImplementedException”类型的第一次机会异常 发生在 NHibernate.dll 中

我们尝试了不同的方法,但都没有奏效。是否可以通过一次查询获得所需的结果?

我有这个模型:

public class Stock
{
    public RawMaterial RawMaterial{ get; set; }
    public int Amount { get; set; }
}

public class RawMaterial
{
    public int Id{ get;set; }
    public string Name { get;set; }
    public IList<SupplierInfo> SupplierInfos{ get;set; }
}

public class SupplierInfo
{
    public int Id{ get;set; }   
    public Supplier Supplier { get;set; }
}

public class Supplier
{
    public int Id { get;set; }
    public string Name { get; set; } 
}

最初我们有一个网格,我们在其中显示每种原材料的可用总库存。我们使用此查询检索该信息:

var list = this.Stocks.Where(x => x.StockType == StockTypeEnum.RawMaterialEntered)
  .GroupBy(i => new { RawMaterialId = i.RawMaterial.Id, RawMaterial = i.RawMaterial.Name })
  .Select(g => new StockSummary
               {
                   TotalAmount = g.Sum(i => i.Amount),
                   ComponentId = g.Key.RawMaterialId,                   
                   Component = g.Key.RawMaterial,                   
               })
               .OrderByDescending(g => g.Component).ToList();

此数据显示在与此类似的表格中:

现在,如上所述,我们想显示提供上述组件的供应商列表。是否可以在一个查询中完成所有操作?

【问题讨论】:

  • 您在寻找hibernate解决方案还是sql server解决方案?我无法开始帮助您进行休眠,但在 sql server 中,您可以轻松地使用东西和 xml。看看这里。 stackoverflow.com/questions/451415/…
  • 您是否在GroupBy 调用中按列表对数据进行分组?据我所知,NHibernate 和 EF 都不支持这种操作。
  • 我会说不,你不能在一个查询中做到这一点。在第一次查询中获取您需要的所有结果,从数据库中加载它们并将它们分组到您的应用程序中。我不确定你想要做什么甚至在 SQL 中是可能的。
  • @Sidewinder94 应用程序中的分组将依赖于手动选择组成员,因为它会要求进行集合比较。我从来没有在这个问题上看到过这样的尝试。
  • @ZoranHorvat 不,它不存在于问题中,但如果 OP 真的需要他的列表分组,这可能是一个解决方案。

标签: c# sql-server linq nhibernate


【解决方案1】:

你可以试试:

var list = this.Stocks
    .Where(x => x.StockType == StockTypeEnum.RawMaterialEntered)
    .GroupBy(i => 
        new
        {
            RawMaterialId = i.RawMaterial.Id,
            RawMaterial = i.RawMaterial.Name
        })
    .Select(g => new StockSummary
    {
        TotalAmount = g.Sum(i => i.Amount),
        ComponentId = g.Key.RawMaterialId,                   
        Component = g.Key.RawMaterial,
        Suppliers = g
            .SelectMany(s => 
                s.RawMaterial.SupplierInfos.Select(j => 
                    new { Id = j.Supplier.Id, Name = j.Supplier.Name }))
            .Distinct()
            .Select(h => new StockItemModel() { Id = h.Id, Name = h.Name })
            .ToList()
    })
    .OrderByDescending(g => g.Component).ToList();

我认为它仍然符合您的要求,并且避免了尝试按列表进行分组。但我不确定它是否可以由 NHibernate 执行。

避免使用 group by 可能会更容易:为什么不使用 RawMaterial 作为查询的根?这需要在RawMaterial 上添加Stocks 集合(或使用子查询)。

猜测this.RawMaterials 存在并且是IQueryable&lt;RawMaterial&gt;,它会是这样的:

var list = this.RawMaterials
    .Where(rm =>
        rm.Stocks.Any(s => s.StockType == StockTypeEnum.RawMaterialEntered))
    .Select(rm => new StockSummary
    {
        TotalAmount = rm.Stocks
            .Where(s => s.StockType == StockTypeEnum.RawMaterialEntered)
            .Sum(s => s.Amount),
        ComponentId = rm.Id,                   
        Component = rm.Name,
        Suppliers = rm.SupplierInfos
            .Select(si =>
                new StockItemModel()
                {
                    Id = si.Supplier.Id,
                    Name = si.Supplier.Name
                })
            .ToList()
    })
    .OrderByDescending(ss => ss.Component).ToList();

我知道这种查询是由 EF 处理的,但我还没有尝试使用 NHibernate 进行此类查询。 (由于延迟加载批处理(如果启用),NHibernate 在加载子集合方面比 EF 好得多。所以我不使用您正在尝试的那种投影。)

【讨论】:

    【解决方案2】:

    首先,您的代码不完整,或者您没有在此处粘贴所有内容。例如,StockTypeStockEnumType 丢失了,为了简单起见,我从我的答案中删除了它们,而不是试图复制你没有显示的内容。无论如何,如果我使用 string.Join(",", ...) 对我来说效果很好,尽管它确实显示了 Id 和 Name,但我认为通过修改 LINQ 语句来调整输出应该没有问题:

            var list = stocks
                .GroupBy(i => new { RawMaterialId = i.RawMaterial.Id, RawMaterial = i.RawMaterial.Name,
                    Suppliers = i.RawMaterial.SupplierInfos.Select(j => new { Id = j.Supplier.Id, Name = j.Supplier.Name })
                })
                .Select(g => new
                {
                    TotalAmount = g.Sum(i => i.Amount),
                    ComponentId = g.Key.RawMaterialId,
                    Component = g.Key.RawMaterial,
                    Suppliers = string.Join(",", g.Key.Suppliers.Select(h => new { Id = h.Id, Name = h.Name }).ToList())
                })
                .OrderByDescending(g => g.Component).ToList();
    

    输出是我的测试数据:

    1 Name3 30.00 (Id = 1, Name = Sup1),(Id = 3, Name = Sup3)

    2 Name2 20.00 (Id = 1, Name = Sup1) ...

    【讨论】:

    • 是的,我忘了添加 StockType,但这些确实与问题无关。你也在使用 Nhibernate 吗?还是完全是内存测试?
    • 这是在内存中,但你的数据模型是否正确并不重要。 LINQ 是对您的数据源的抽象,它允许您操作数据,无论它是内存中的、SQL 还是非 SQL 等
    • 这很重要,因为 Linq To SQL 被转换为 SQL,我得到了 Nhibernate 异常。我想编写 Linq,以便它在 SQL 中生成最少的查询。
    • @Dzyann 那么您是否尝试过上面的代码?还请提供一些堆栈跟踪。这也可以通过 this.Stocks.ToList().Where... 来解决
    • 你的代码和我的基本一样,不过我确实试过了。如果您执行 Stocks.ToList() ,它实际上会将所有内容都带入记忆中。
    猜你喜欢
    • 2010-12-31
    • 2010-11-15
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 2016-05-26
    • 2011-04-18
    • 1970-01-01
    相关资源
    最近更新 更多