代码之家  ›  专栏  ›  技术社区  ›  Ethan J. Brown

Linq到Sql-使用众所周知的静态类型在运行时更改排序顺序

  •  0
  • Ethan J. Brown  · 技术社区  · 16 年前

    这不是关于“如何动态排序(基于用户提供的任意字段)”的另一个问题

    问题是——当我提前知道潜在排序时,如何更改排序顺序?(从而避免反射/自定义表达式构建通常与真正的动态排序关联。)

    以较大查询的子查询(本例中简称为)为例:

    (from solutionIds in context.csExtendedQAIncident_Docs
        where solutionIds.tiRecordStatus == 1
        && (from solutionProductAssocation in context.csProductDocs
               where solutionProductAssocation.iSiteId == Settings.Current.WebUtility().Onyx.SiteId
               && (from allowedProduct in context.KB_User_Allowed_Products
                      where allowedProduct.UserId == userId
                      select allowedProduct.ModelCode
                   ).Contains(solutionProductAssocation.chModelCd)
               select solutionProductAssocation.chIdNo).Distinct().Contains(solutionIds.chIdNo)
    ).OrderByDescending(s => s.dtUpdateDate)
    .Select(s => s.chIdNo)
    .Take(count ?? Settings.Current.WCFServices().Output.HomePage.MaxRows)
    

    OrderByDescending部分的工作方式与我预期的一样。

    现在--我想用下面的公式计算出来:

    Expression<Func<csExtendedQAIncident_Doc, IComparable>> ordering =  (s) => s.dtUpdateDate;
    if (viewType == HomepageViewType.MostViewed)
       ordering = (s) => s.vchUserField8;
    else if (viewType == HomepageViewType.MostEffective)
       ordering = (s) => s.vchUserField4;
    

    然后使用:

    OrderByDescending(ordering)
    

    Unsupported overload used for query operator 'OrderByDescending'.  
    

    这当然来自System.Data.Linq.SqlClient.QueryConverter的内心深处——特别是VisiteSquenceOperator或Call。反映该代码表明,OrderByDescending必须满足以下条件才能正确计算。”mc'是传递到方法中的MethodCallExpression。

    if (((mc.Arguments.Count != 2) || !this.IsLambda(mc.Arguments[1]))
        || (this.GetLambda(mc.Arguments[1]).Parameters.Count != 1))
    {
       break;
    }
    

    很明显,我没有正确地构造表达式。如果不在这里进一步深入,有人知道如何正确构造排序表达式吗?

    2 回复  |  直到 16 年前
        1
  •  3
  •   Ben M    16 年前

    我认为代码中不受支持的部分是使用 IComparable 作为排序表达式的常规返回类型。如果你考虑简单使用 OrderByDescending ,编译器生成的lambda表达式的返回类型为您排序依据的属性类型:例如 Expression<Func<csExtendedQAIncident_doc, string>> 对于字符串属性。

    一个可能的答案是,首先创建一个无序查询,尽管我不确定它是否适用于您的情况:

    IQueryable<Foo> unorderedQuery = from f in db.Foo select f;
    

    IOrderedQueryable<Foo> orderedQuery = unorderedQuery
        .OrderBy(f => f.DefaultSortKey);
    
    if (sortBy == SortByName)
        orderedQuery = unorderedQuery.OrderBy(f => f.Name);
    else if (sortBy == SortByDate)
        orderedQuery = unorderedQuery.OrderBy(f => f.Date);
    // etc.
    
        2
  •  0
  •   ShuggyCoUk    16 年前

    我认为,除非这两个可能的领域有了共同的目标,否则这是行不通的 类型。

    例如,如果这两个字段都是日期时间:

    Expression<Func<csExtendedQAIncident_Doc, DateTime>> ordering = 
        s => s.dtUpdateDate;
    if (viewType == HomepageViewType.MostViewed)
       ordering = (s) => s.vchUserField8;  // a DateTime
    else if (viewType == HomepageViewType.MostEffective)
       ordering = (s) => s.vchUserField4;  // another  DateTime
    

    然后,这将工作得很好(我测试了它,它工作了)

    相反,您可以通过一系列嵌套的switch/if语句或通过构造字典或类似的结构来获取它们来执行每类型的顺序。

    精确的 查询的类型,而不仅仅是一个IComparable。。。