C# 使用实体框架的规范模式(按属性排序)

C# 使用实体框架的规范模式(按属性排序),c#,entity-framework,sorting,linq-to-entities,specification-pattern,C#,Entity Framework,Sorting,Linq To Entities,Specification Pattern,我想编写一些API来使用LINQ2Entities对服务器端(SQLServer)的实体进行排序 我有一个类,其中包含表示实体排序字段和排序方向的表达式: public class SortOption<TEntity> { public SortOption(Expression<Func<TEntity, dynamic>> keySelector, bool ascending = true)

我想编写一些API来使用LINQ2Entities对服务器端(SQLServer)的实体进行排序

我有一个类,其中包含表示实体排序字段和排序方向的表达式:

    public class SortOption<TEntity>
    {
       public SortOption(Expression<Func<TEntity, dynamic>> keySelector, 
            bool ascending = true)
        {
            KeySelector = keySelector;
            Ascending = ascending;
        }

       public Expression<Func<TEntity, dynamic>> KeySelector { get; private set; }
       public bool Ascending { get; private set; }
    }
例如(按发布字段排序):

或者(如果我想按修改字段订购)

of(如果我想按Id字段订购)

我为此任务工作了好几天,但找不到解决问题的答案。

尝试使用以下方法:

public static class QueryableEx
{
    public static IOrderedQueryable<TSource> OrderByEx<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, object>> keySelector)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (keySelector == null)
        {
            throw new ArgumentNullException("keySelector");
        }

        // While the return type of keySelector is object, the "type" of 
        // keySelector.Body is the "real" type *or* it is a
        // Convert(body). We rebuild a new Expression with this "correct" 
        // Body (removing the Convert if present). The return type is
        // automatically chosen from the type of the keySelector.Body .
        Expression body = keySelector.Body;

        if (body.NodeType == ExpressionType.Convert)
        {
            body = ((UnaryExpression)body).Operand;
        }

        LambdaExpression keySelector2 = Expression.Lambda(body, keySelector.Parameters);
        Type tkey = keySelector2.ReturnType;

        MethodInfo orderbyMethod = (from x in typeof(Queryable).GetMethods()
                                    where x.Name == "OrderBy"
                                    let parameters = x.GetParameters()
                                    where parameters.Length == 2
                                    let generics = x.GetGenericArguments()
                                    where generics.Length == 2
                                    where parameters[0].ParameterType == typeof(IQueryable<>).MakeGenericType(generics[0]) && 
                                        parameters[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(generics[0], generics[1]))
                                    select x).Single();

        return (IOrderedQueryable<TSource>)source.Provider.CreateQuery<TSource>(Expression.Call(null, orderbyMethod.MakeGenericMethod(new Type[]
        {
            typeof(TSource),
            tkey
        }), new Expression[]
        {
            source.Expression,
            Expression.Quote(keySelector2)
        }));
    }
}
公共静态类QueryableEx
{
公共静态IOrderedQueryable OrderByEx(此IQueryable源、表达式键选择器)
{
if(source==null)
{
抛出新的ArgumentNullException(“源”);
}
if(keySelector==null)
{
抛出新ArgumentNullException(“KeySelect”);
}
//当keySelector的返回类型为object时
//主体是“真实”类型*或*它是
//转换(正文)。我们用这个“正确”重新生成一个新表达式
//正文(如果存在,则删除转换)。返回类型为
//从KeySelect.Body的类型中自动选择。
表达式body=keySelector.body;
if(body.NodeType==ExpressionType.Convert)
{
body=((一元表达式)body).操作数;
}
LambdaExpression keySelector2=Expression.Lambda(body,keySelector.Parameters);
类型tkey=KeySelector 2.ReturnType;
MethodInfo orderbyMethod=(来自typeof(Queryable.GetMethods()中的x)
其中x.Name==“OrderBy”
让参数=x.GetParameters()
其中parameters.Length==2
让泛型=x.GetGenericArguments()
其中,泛型.Length==2
其中参数[0]。参数类型==typeof(IQueryable)。MakeGenericType(泛型[0])&&
参数[1]。参数类型==typeof(表达式)。MakeGenericType(typeof(Func)。MakeGenericType(泛型[0],泛型[1]))
选择x.Single();
return(IOrderedQueryable)source.Provider.CreateQuery(Expression.Call)(null,orderbyMethod.MakeGenericMethod)(新类型[])
{
类型(TSource),
tkey
}),新表达式[]
{
来源.表达式,
Expression.Quote(keySelector2)
}));
}
}
您必须编写一个
OrderByAscending
,但将
OrderBy
替换为
OrderByAscending
也是一样的。该方法重写
表达式
,以使用“right”类型

该代码的灵感来源于。

尝试使用以下方法:

public static class QueryableEx
{
    public static IOrderedQueryable<TSource> OrderByEx<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, object>> keySelector)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (keySelector == null)
        {
            throw new ArgumentNullException("keySelector");
        }

        // While the return type of keySelector is object, the "type" of 
        // keySelector.Body is the "real" type *or* it is a
        // Convert(body). We rebuild a new Expression with this "correct" 
        // Body (removing the Convert if present). The return type is
        // automatically chosen from the type of the keySelector.Body .
        Expression body = keySelector.Body;

        if (body.NodeType == ExpressionType.Convert)
        {
            body = ((UnaryExpression)body).Operand;
        }

        LambdaExpression keySelector2 = Expression.Lambda(body, keySelector.Parameters);
        Type tkey = keySelector2.ReturnType;

        MethodInfo orderbyMethod = (from x in typeof(Queryable).GetMethods()
                                    where x.Name == "OrderBy"
                                    let parameters = x.GetParameters()
                                    where parameters.Length == 2
                                    let generics = x.GetGenericArguments()
                                    where generics.Length == 2
                                    where parameters[0].ParameterType == typeof(IQueryable<>).MakeGenericType(generics[0]) && 
                                        parameters[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(generics[0], generics[1]))
                                    select x).Single();

        return (IOrderedQueryable<TSource>)source.Provider.CreateQuery<TSource>(Expression.Call(null, orderbyMethod.MakeGenericMethod(new Type[]
        {
            typeof(TSource),
            tkey
        }), new Expression[]
        {
            source.Expression,
            Expression.Quote(keySelector2)
        }));
    }
}
公共静态类QueryableEx
{
公共静态IOrderedQueryable OrderByEx(此IQueryable源、表达式键选择器)
{
if(source==null)
{
抛出新的ArgumentNullException(“源”);
}
if(keySelector==null)
{
抛出新ArgumentNullException(“KeySelect”);
}
//当keySelector的返回类型为object时
//主体是“真实”类型*或*它是
//转换(正文)。我们用这个“正确”重新生成一个新表达式
//正文(如果存在,则删除转换)。返回类型为
//从KeySelect.Body的类型中自动选择。
表达式body=keySelector.body;
if(body.NodeType==ExpressionType.Convert)
{
body=((一元表达式)body).操作数;
}
LambdaExpression keySelector2=Expression.Lambda(body,keySelector.Parameters);
类型tkey=KeySelector 2.ReturnType;
MethodInfo orderbyMethod=(来自typeof(Queryable.GetMethods()中的x)
其中x.Name==“OrderBy”
让参数=x.GetParameters()
其中parameters.Length==2
让泛型=x.GetGenericArguments()
其中,泛型.Length==2
其中参数[0]。参数类型==typeof(IQueryable)。MakeGenericType(泛型[0])&&
参数[1]。参数类型==typeof(表达式)。MakeGenericType(typeof(Func)。MakeGenericType(泛型[0],泛型[1]))
选择x.Single();
return(IOrderedQueryable)source.Provider.CreateQuery(Expression.Call)(null,orderbyMethod.MakeGenericMethod)(新类型[])
{
类型(TSource),
tkey
}),新表达式[]
{
来源.表达式,
Expression.Quote(keySelector2)
}));
}
}
您必须编写一个
OrderByAscending
,但将
OrderBy
替换为
OrderByAscending
也是一样的。该方法重写
表达式
,以使用“right”类型


代码的灵感来源于。

@malonowa您使用的是
OrderByEx
方法吗?是的,我更改了查询,如下面的query=\u dbSet。OrderByEx(sortOptions.KeySelector)并对SortOption类中的ctor和属性“KeySelector”进行了更改:KeySelector是Expression@malonowa固定的。围绕大注释修改代码。从大评论到LambdaExpression keySelector2(包括)Xanatos,我不明白它是如何工作的,但它是如何工作的!多谢各位!这对于OrderBy和OrderByDescending非常有效,但是我尝试重用ThenBy和ThenByDescending,并在分配了
MethodInfor orderbyMethod
的行上获取“Sequence contains no elements.”。任何帮助都将不胜感激。我有小白鼠
"LINQ to Entities only supports casting EDM primitive or enumeration types.".
 "Unable to cast the type 'System.Nullable`1[[System.DateTime, mscorlib, 
    Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' to type
     'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types."
 "Unable to cast the type 'System.DateTime' to type 'System.Object'.
 LINQ to Entities only supports casting EDM primitive or enumeration types."
 "Unable to cast the type 'System.Guid' to type 'System.Object'. 
 LINQ to Entities only supports casting EDM primitive or enumeration types."
public static class QueryableEx
{
    public static IOrderedQueryable<TSource> OrderByEx<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, object>> keySelector)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (keySelector == null)
        {
            throw new ArgumentNullException("keySelector");
        }

        // While the return type of keySelector is object, the "type" of 
        // keySelector.Body is the "real" type *or* it is a
        // Convert(body). We rebuild a new Expression with this "correct" 
        // Body (removing the Convert if present). The return type is
        // automatically chosen from the type of the keySelector.Body .
        Expression body = keySelector.Body;

        if (body.NodeType == ExpressionType.Convert)
        {
            body = ((UnaryExpression)body).Operand;
        }

        LambdaExpression keySelector2 = Expression.Lambda(body, keySelector.Parameters);
        Type tkey = keySelector2.ReturnType;

        MethodInfo orderbyMethod = (from x in typeof(Queryable).GetMethods()
                                    where x.Name == "OrderBy"
                                    let parameters = x.GetParameters()
                                    where parameters.Length == 2
                                    let generics = x.GetGenericArguments()
                                    where generics.Length == 2
                                    where parameters[0].ParameterType == typeof(IQueryable<>).MakeGenericType(generics[0]) && 
                                        parameters[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(generics[0], generics[1]))
                                    select x).Single();

        return (IOrderedQueryable<TSource>)source.Provider.CreateQuery<TSource>(Expression.Call(null, orderbyMethod.MakeGenericMethod(new Type[]
        {
            typeof(TSource),
            tkey
        }), new Expression[]
        {
            source.Expression,
            Expression.Quote(keySelector2)
        }));
    }
}