1

关于以下查询有什么问题的任何提示?

return new ItemPricesViewModel()
            {
                Source = (from o in XpoSession.Query<PRICE>()
                          select new ItemPriceViewModel()
                          {
                              ID = o.ITEM_ID.ITEM_ID,
                              ItemCod = o.ITEM_ID.ITEM_COD,
                              ItemModifier = o.ITEM_MODIFIER_ID.ITEM_MODIFIER_COD,
                              ItemName = o.ITEM_ID.ITEM_COD,
                              ItemID = o.ITEM_ID.ITEM_ID,
                              ItemModifierID = o.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID,
                              ItemPrices = (from d in o
                                                where d.ITEM_ID.ITEM_ID == o.ITEM_ID.ITEM_ID && d.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID == o.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID
                                                select new Price()
                                                {
                                                    ID = o.PRICE_ID,
                                                    PriceList = o.PRICELIST_ID.PRICELIST_,
                                                    Price = o.PRICE_

                                                }).ToList()
                          }).ToList()
            };
  1. o in subquery is in read,我收到消息“找不到源类型的查询模式的实现。'在哪里'找不到。”
  2. 我想有不同的 ItemID,ItemModifier:我应该创建一个自定义的 IEqualityComparer 来做到这一点吗?

谢谢!

4

2 回答 2

1

它似乎XPO无法响应这种情况。作为参考,这是您可以使用的DbContext.

听起来你可能想要一个GroupBy. 尝试这样的事情。

var result = dbContext.Prices
   .GroupBy(p => new {p.ItemName, p.ItemTypeName)
   .Select(g => new Item
                 {
                     ItemName = g.Key.ItemName,
                     ItemTypeName = g.Key.ItemTypeName,
                     Prices = g.Select(p => new Price 
                                                {
                                                    Price = p.Price
                                                }
                                       ).ToList()

                 })
 .Skip(x)
 .Take(y)
 .ToList();
于 2012-07-02T21:39:10.633 回答
0

可能的原因

一般来说,XPO 在大多数情况下都不支持“自由连接”。它被明确地写在他们的知识库或问答网站的某个地方。如果我再次点击那篇文章,我会附上它的链接。

在您的原始代码示例中,您试图在 INNER 查询中执行“自由联接”。'WHERE' 子句是按键连接的,可能是导航的,但它还包含一个由“修饰符”组成的额外过滤器,这可能不是关系定义的一部分。

此外,该查询尝试IQueryable<PRICE> o在内部查询中重用 - 实际上似乎受到 XPO 的支持 - 但如果您将任何预过滤('where')添加到顶级 'o',它再次中断的可能性很高。

文档声明 XPO 仅支持导航连接,沿着由 XPObjects 中定义的属性和/或 xpcollections 形成的路径。这适用于整个 XPO,所以 XPQuery 也是如此。所有其他类型的连接都称为“自由连接”,并且:

  • XPO 通过获取相关对象、从中提取键值并将查询重写为具有一系列部分查询的多次往返,这些部分查询使用 WHERE-id-IN-(@p0,@p1,@p2, ...) - 但这只发生在一些最简单的情况下
  • 或“不完全支持”,这意味着它们会抛出异常并要求您手动拆分查询或改写它

可能的直接解决方案

如果 ITEM_ID 是 PRICE 类中的关系和 XPCollection,那么您可以重写查询,以便它获取 PRICE对象,然后构建结果对象并使用 PRICE对象的属性初始化其字段。就像是:

return new ItemPricesViewModel()
{
    Source = (from o in XpoSession.Query<PRICE>().AsEnumerable()
              select new ItemPriceViewModel()
              {
                  ID = o.ITEM_ID.ITEM_ID,
                  ItemCod = o.ITEM_ID.ITEM_COD,
                  ....
                  ItemModifierID = o.ITEM_MODIFIER_ID.ITEM_MODIFIER_ID,
                  ItemPrices = (from d in o
                                where d.ITEM_ID.ITEM_ID == ....
                                select new Price()
    ....          ....          ....
};

请注意中断查询并确保首先获取 PRICE 对象而不是仅仅尝试翻译查询的“AsEnumerable”。这很可能会“正常工作”。

此外,将查询拆分为显式阶段有时有助于 XPO 对其进行分析:

return new ItemPricesViewModel()
{
    Source = (from o in XpoSession.Query<PRICE>()
              select new
              {
                  id = o.ITEM_ID.ITEM_ID,
                  itemcod = o.ITEM_ID.ITEM_COD,
                  ....
              }
          ).AsEnumerable()
          .Select(temp => 
              select new ItemPriceViewModel()
              {
                  ID = temp.id
                  ItemCod = temp.itemcod,
                  ....
                  ItemPrices = (from d in XpoSession.Query<PRICE>()
                                where d.ITEM_ID.ITEM_ID == ....
                                select new Price()
    ....          ....          ....
};

在这里,请注意,我首先从服务器获取项目数据,然后在“客户端”上构建项目,然后构建所需的分组。请注意,我不能再引用该变量o了。在这些精确的案例和示例中,不出所料,第二个(拆分的)可能会比第一个慢,因为它会获取所有 PRICE,然后通过额外的查询重新获取分组,而第一个只会获取所有 PRICE 和然后将根据已经获取的 PRICE 计算内存中的组。这不是我懒惰的副作用,但在重写 LINQ 查询时这是一个常见的陷阱,所以我将它作为警告包括在内:)

对于您的情况,不建议使用这两个代码示例,因为它们的性能可能很差,特别是如果您的表中有很多 PRICE,这很有可能。我将它们包括在内,仅作为一个示例,说明如何重写查询以简化其结构,以便 XPO 可以在不窒息的情况下吃掉它。但是,您必须非常小心并注意小细节,因为您很容易破坏性能。

观察和真正的解决方案

但是,值得注意的是,它们并不比您的原始查询差多少。它本身就很差,因为它试图从表中执行接近 O(N^2) 行的操作,只是为了按“ITEM_ID”对 te 行进行分组,然后将结果格式化为单独的对象。如果做得好,它将类似于 O(N lg N)+O(N),因此无论是否支持,您使用 GroupBy 的替代尝试肯定是一个更好的方法,我真的很高兴您自己找到了它.

很多时候,当您像我在上面所做的那样尝试拆分/简化 XPQuery 表达式时,您会隐含地重新考虑问题并找到一种更简单、更简单的方法来表达最初不受支持或刚刚崩溃的查询。

不幸的是,您的查询实际上非常简单。对于一个不能“只是改写”的非常复杂的查询,拆分成多个阶段并使一些连接过滤器在“客户端”工作是不可避免的。但同样,在 XPCollections 或 XPViews 上使用 CritieriaOperators 也是不可能的,所以要么我们必须忍受它或使用简单的直接手工 SQL ..

边注:

整个 XPO 存在“自由连接”的问题,它们不仅在 XPQuery 中“不完全支持”,而且在 XPCollection、XPView、CriteriaOperators 等中也没有太多支持。但是,值得注意的是,至少在 DX11 的“我的版本”中,XPQuery 的 LINQ 支持非常

我遇到过很多正确的 LINQ 查询是:

  • 抛出“NotSupportedException”,主要是在 FreeJoins 中,但也经常使用复杂的 GroupBy 或 Select-with-Projection、GroupJoin 和许多其他 - 有时甚至 Distinct(!) 似乎出现故障
  • 在一些适当的类型转换中抛出“NullReferenceExceptions”(XPO 试图解释一个将 INT/NULL 作为对象的列..),我经常不得不编写一些完全奇怪和人为的表达式,foo!=null && foo.bar!=123而不是foo = 123尽管 'foo' 是一个public int Foo {get;set;},这一切都是因为 DX 无法正确处理数据库中的 NULL(因为 XPO 为该属性创建了可为空的 INT 列……但这是另一回事)
  • 从其他构造中抛出其他随机 ArgumentException/InvalidOperation 异常
  • 甚至不正确地分析查询结构,例如这个通常是有效的:

    session.Query<ABC>()
         .Where( abc => abc.foo == "somefilter" )
         .Select( abc => new { first = abc, b = abc } )
         .ToArray();
    

    但像这样的事情通常会抛出:

    session.Query<ABC>()
         .Select( abc => new { first = abc, b = abc } )
         .Where ( temp => temp.first.foo == "somefilter" )
         .ToArray();
    

    但这一个是有效的:

    session.Query<ABC>()
         .Select( abc => new { first = abc, b = abc } )
         .ToArray()
         .Where ( temp => temp.first.foo == "somefilter" )
         .ToArray();
    

    中间代码示例通常抛出一个错误,表明 XPO 层试图在 ABC 类中查找“.first.foo”路径,这显然是错误的,因为此时元素类型ABC不再是匿名类,而是a'匿名类。

免责声明

我已经注意到这一点,但让我重复一遍:这些观察结果与 DX11 相关,而且很可能更早。我不知道在 DX12 及更高版本中修复了什么(如果有的话!)。

于 2013-04-24T09:00:34.123 回答