Linq To Sql-使用众所周知的静态类型在运行时更改排序顺序 [英] Linq To Sql - Changing Sort Order At Run-Time with well known static typing
问题描述
这不是关于如何动态排序(基于用户提供的任意字段)吗?"的另一个问题.
This is not another question about 'How Can I Sort Dynamically (based on an arbitrary user provided field)?'
问题是-当我提前知道潜在的排序方式时,如何更改排序顺序? (从而避免通常与真正的动态排序相关联的反射/自定义表达式构建.)
The question is -- how can I change sort order when I know the potential sorts in advance? (And thus avoid reflection / custom Expression building typically associated with truly dynamic sorting.)
以一个较大查询的此子查询(此示例为简称)为例:
Take for instance this subquery (shortened for this example) of a larger query:
(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部分按预期工作.
The OrderByDescending portion works as I would expect.
现在-我想像以下那样将其排除在外:
Now -- I want to factor that out like the following:
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)
这确实可以编译,但是在运行时会炸毁.
This does compile, but blows up at run-time.
Unsupported overload used for query operator 'OrderByDescending'.
这当然来自System.Data.Linq.SqlClient.QueryConverter的深层内容-特别是VisitSequenceOperatorCall.反映该代码表明,必须满足以下条件才能正确评估OrderByDescending. "mc"是传递给方法的MethodCallExpression.
This of course comes from deep in the bowels of System.Data.Linq.SqlClient.QueryConverter -- in particular VisitSequenceOperatorCall. Reflectoring that code reveals that the following conditions must be met for OrderByDescending to properly evaluate. 'mc' is the MethodCallExpression passed into the method.
if (((mc.Arguments.Count != 2) || !this.IsLambda(mc.Arguments[1]))
|| (this.GetLambda(mc.Arguments[1]).Parameters.Count != 1))
{
break;
}
从本质上讲,MethodCallExpression必须具有2个参数,其中第二个必须是具有单个参数(可能是排序字段)的Expressions.LambdaExpression.如果该代码崩溃,则会抛出我所收到的异常.
So essentially that MethodCallExpression has to have 2 arguments, the second of which has to be a Expressions.LambdaExpression with a single parameter (presumably the sort field). If that code breaks out, the exception that I got is thrown.
很明显,我没有正确构造表达式.在这里不做进一步探讨,有谁知道如何正确构造排序表达式?
So clearly I have not constructed the expression correctly. Without digging in any further here, does anyone know how to correctly construct the sorting Expression?
推荐答案
我认为您的代码不支持的部分是使用IComparable
作为您的排序表达式的常规返回类型.如果考虑普通使用OrderByDescending
,则编译器生成的lambda表达式的返回类型为您要排序的属性的类型:例如,字符串属性的Expression<Func<csExtendedQAIncident_doc, string>>
.
I think the unsupported part of your code is the use of IComparable
as a general return type for your ordering expression. If you consider the plain use of OrderByDescending
, the compiler-generated lambda expression has a return type of the type of the property that you're ordering by: for example, an Expression<Func<csExtendedQAIncident_doc, string>>
for a string property.
一个可能的答案,尽管我不确定它是否适合您的情况,但首先创建一个无序查询:
One possible answer, although I'm not sure whether it works in your case, is to first create an unordered query:
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.
这篇关于Linq To Sql-使用众所周知的静态类型在运行时更改排序顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!