4

有了这个查询,我得到一个 InvalidOperationException:“应用单一聚合的集合必须为空或只包含一个项目”。

List<int> olsesUsedForTaskCompletion = new List<int>();
olsesUsedForTaskCompletion.AddRange(task.OrderLineSpecifications_QtysCompleted.Select(ols => ols.Key).ToList());

var allRelatedTasks = (from t in new XPQuery<Core.Model.Task.Task>(session, true)
                       join ols in new XPQuery<OrderLineSpecification>(session, true)
                       on t.PickSpecification equals ols.PickSpecification
                       where t.PickSpecification == task.PickSpecification
                          && t.Status != TaskStatuses.Cancelled
                          && olsesUsedForTaskCompletion.Contains(ols.Oid)
                       select t).ToList();

我希望在加入时仅获取具有特定 ID 的 OLS。我究竟做错了什么?

这是堆栈跟踪:

at DevExpress.Xpo.Helpers.InTransactionLoader.ProcessException(Exception ex)
   at DevExpress.Xpo.Helpers.InTransactionLoader.ProcessAnalyzeAndExecQuery()
   at DevExpress.Xpo.Helpers.InTransactionLoader.Process()
   at DevExpress.Xpo.Helpers.InTransactionLoader.GetObjects(ObjectsQuery[] queries)
   at DevExpress.Xpo.Helpers.InTransactionLoader.GetObjects(Session session, ObjectsQuery[] queries)
   at DevExpress.Xpo.Session.<>c__DisplayClass16.<GetObjectsInTransaction>b__14()
   at DevExpress.Xpo.Logger.LogManager.Log[T](String category, LogHandler`1 handler, MessageHandler`1 createMessageHandler)
   at DevExpress.Xpo.Session.GetObjectsInTransaction(XPClassInfo classInfo, CriteriaOperator condition, SortingCollection sorting, Int32 skipSelectedRecords, Int32 topSelectedRecords, Boolean selectDeleted)
   at DevExpress.Xpo.XPQueryBase.SessionGetObjects(XPClassInfo classInfo, CriteriaOperator condition, SortingCollection sorting, Int32 skipSelectedRecords, Int32 topSelectedRecords, Boolean selectDeleted)
   at DevExpress.Xpo.XPQueryBase.GetObjects()
   at DevExpress.Xpo.XPQueryBase.Enumerate(Type type)
   at DevExpress.Xpo.XPQuery`1.GetEnumerator()
   at DevExpress.Xpo.XPQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Davanti.WMS.Services.Implementation.Outbound.OrderLineSpecificationStatusService.ChangeStatusToPickedToShipToStageOrStaged(Session session, IList`1 tasks, IList`1 olsWithoutTasks) in c:\Corax\DAV_WMS\DEV\SRC\APP\WMS\Davanti.WMS.Services.Implementation\Outbound\OrderLineSpecificationStatusService.cs:line 471

更新:经过一番挣扎后,我所做的是: - 采用了另一种方法。我不知道您是否可以获取它的业务逻辑,但我首先使用 OLS 生成了一个列表,然后从中生成了另一个带有选择规范的列表。后来我对Tasks做了一个简单的查询。

// compose list of olses for which status will be updated
    List<OrderLineSpecification> olSpecs = (from ols in new XPQuery<OrderLineSpecification>(session, true)
                                            where ols.Status != OrderLineSpecificationStatus.Cancelled 
                                                    //...
                                                    && ols.PickSpecification == task.PickSpecification
                                                    && (olsesUsedForTaskCompletion.Count == 0
                                                        || (olsesUsedForTaskCompletion.Contains(ols.Oid) && ols.QtyOrdered == ols.QtyPicked))
                                            select ols).ToList();

    var pickSpecificationKeys = (from ols in olSpecs select ols.PickSpecification.Oid).Distinct().ToList();

    var allRelatedTasks = (from t in new XPQuery<Core.Model.Task.Task>(session, true)
                            where pickSpecificationKeys.Contains(t.PickSpecification.Oid)
                                    && t.Status != TaskStatuses.Cancelled
                            select t).ToList();

我只是希望这能奏效,无论客户的数据库结构,双重引用等等...... :)

4

1 回答 1

1

查询中的 Select 部分实例化了一个持久对象,这意味着结果序列中的每个元素都是唯一的(一个持久对象不能两次加载到同一个 Session 中)。这就是为什么将查询转换为单个聚合函数的原因。错误的原因是Join表达式中innerKey和outerKey的匹配可能会产生从outer序列中选择的item的重复条目。  

如果在您的场景中预计不会出现重复,那么您需要修复数据库中的数据或重写查询以考虑到这一点。例如,您可以使用“join into”运算符对重复记录进行分组:

from t in new XPQuery<Core.Model.Task.Task>(session, true)
   join ols in new XPQuery<OrderLineSpecification>(session, true)
   on t.PickSpecification equals ols.PickSpecification
   into tg
   where tg.key == task.PickSpecification
      && tg.Any(gi.Status != TaskStatuses.Cancelled && olsesUsedForTaskCompletion.Contains(ols.Oid))
   select t

替换查询中的序列也可能有助于避免某些情况下的错误,但您将在结果序列中出现重复的对象引用:

from ols in new XPQuery<OrderLineSpecification>(session, true)
   join t in new XPQuery<Core.Model.Task.Task>(session, true)
   on ols.PickSpecification equals t.PickSpecification
   where ols.PickSpecification == task.PickSpecification
      && t.Status != TaskStatuses.Cancelled
      && olsesUsedForTaskCompletion.Contains(ols.Oid)
   select t

如果您对结果序列中的重复记录感到满意,我建议您只需在 Select 语句中添加一个投影,这样查询就不需要实例化持久对象。

from t in new XPQuery<Core.Model.Task.Task>(session, true)
   join ols in new XPQuery<OrderLineSpecification>(session, true)
   on t.PickSpecification equals ols.PickSpecification
   where t.PickSpecification == task.PickSpecification
      && t.Status != TaskStatuses.Cancelled
      && olsesUsedForTaskCompletion.Contains(ols.Oid)
   select new { SomeProperty = t.SomeProperty, AnotherProperty = t.AnotherProperty }

PS:如果以上都不适用于您的特定情况,请直接联系DevExpress 支持服务。您的问题对 XPO 来说太具体了,因此您很可能会在那里获得合格的答案。

于 2017-06-19T15:31:43.223 回答