1

私はこのコードを持っています:

public void CreateOrdering(string field, string direction)
{
    //direction : ASC/DESC
    var result = context.MyTable
        .Where(x => x.Code > 5)
        .OrderBy()
        .Skip(10)
        .Take(5)
        .ToList<MyTable>();
}

言い換えると、メソッドがあります。このメソッドは、順序付け用の文字列フィールド名と方向 (「ASC」、「DESC」) として受け取ります。

引数で受け取ったフィールドと方向でオーダーを作成したいと思います。私はできる必要があります:

  1. このクエリで昇順と降順を実行できるようにしたい
  2. プログラミングで順序付けフィールドを設定します。ここCodeは後でId、または他の...
  3. 順序付けは、返されたリストではなく、SQL Server 側で行う必要があります

ありがとう、

4

5 に答える 5

3

linq 構文を許可する拡張メソッドでリフレクションを使用できます。

public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string field, string direction)
{
    string orderByMethod = (direction == "ASC") ? "OrderBy" : (direction == "DESC" ? "OrderByDescending" : null);
    if(orderByMethod == null) throw new ArgumentException();

    var propertyInfo = typeof (TSource).GetProperty(field);
    var entityParam = Expression.Parameter(typeof(TSource), "e");
    Expression columnExpr = Expression.Property(entityParam, propertyInfo);
    LambdaExpression columnLambda = Expression.Lambda(columnExpr, entityParam);

    MethodInfo orderByGeneric =  typeof (Queryable).GetMethods().Single(m => m.Name == orderByMethod
                                                    && m.GetParameters().Count() == 2
                                                    && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>)
                                                    && m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>));

    MethodInfo orderBy = orderByGeneric.MakeGenericMethod(new [] {typeof(TSource), propertyInfo.PropertyType});

    return (IQueryable<TSource>) orderBy.Invoke(null, new object[] { source, columnLambda });
}

サンプル使用:

internal class SomeType
{
    public string StringValue { get; set; }
}

IQueryable<SomeType> l = new List<SomeType>
    {
        new SomeType {StringValue = "bbbbb"},
        new SomeType {StringValue = "cccc"},
        new SomeType {StringValue = "aaaa"},
        new SomeType {StringValue = "eeee"},
    }.AsQueryable();

var asc = l.OrderBy("StringValue", "ASC");
var desc = l.OrderBy("StringValue", "DESC");

またはあなたの例のために:

context.MyTable
        .Where(x => x.Code > 5)
        .OrderBy(field, direction)
        .Skip(10)
        .Take(5)
        .ToList<MyTable>();
于 2012-09-19T18:16:50.613 に答える
2

私はあなたの質問を誤解したかもしれませんが、あなたはただそうすることはできません:

上昇

.OrderBy(x => x.Property)

降順

.OrderByDescending(x => x.Property)

アップデート

必要なのはDynamicLINQです。ただし、実行しようとしていることは非常に複雑になる可能性があります。簡単な回避策として、次のようなことができます。

var result = context.MyTable
                    .Where(x => x.Code > 15);

if (direction == "ASC")
{
    result = result.OrderBy(field);
}
else
{
    result = result.OrderByDescending(field);
}

result = result.Skip(10)
               .Take(5)
               .ToList<MyTable>();
于 2012-09-19T08:42:34.453 に答える
1
void Main() {
    // Ascending by some other property
    CreateOrdering(item => item.SomeProperty, SortDirection.Ascending).Dump("Ascending order for SomeClass.SomeProperty");
    // Descending by some other property
    CreateOrdering(item => item.SomeProperty, SortDirection.Descending).Dump("Descending order for SomeClass.SomeProperty");
    // Ascending by the Code property
    CreateOrdering(item => item.Code, SortDirection.Ascending).Dump("Ascending order for SomeClass.Code");
    // Descending by the Code property
    CreateOrdering(item => item.Code, SortDirection.Descending).Dump("Descending order for SomeClass.Code");
}

// I reccomend not using bare strings, and instead use an enum
public enum SortDirection {
     Ascending = 0,
     Descending = 1
}
// Define other methods and classes here
public List<SomeClass> CreateOrdering<T>(Expression<Func<SomeClass, T>> field, SortDirection direction) {
    // query does not get executed yet, because we have not enumerated it.
    var query = context.MyTable
        .Where(x => x.Code > 5);

    if (direction.Equals(SortDirection.Ascending)) {
        query = query.OrderBy (field);
    } else {
        query = query.OrderByDescending (field);
    }

    // query gets executed when the call ToList is made.
    return query.Skip(10)
                .Take(5)
                .ToList();
}

public static class context {
    private static List<SomeClass> _MyTable = new List<SomeClass>() {
        new SomeClass("A", 4), new SomeClass("B", 5), new SomeClass("C", 6),
        new SomeClass("D", 7), new SomeClass("E", 8), new SomeClass("F", 9),
        new SomeClass("G", 10), new SomeClass("H", 11), new SomeClass("I", 12),
        new SomeClass("J", 13), new SomeClass("K", 14), new SomeClass("L", 15),
        new SomeClass("M", 16), new SomeClass("N", 17), new SomeClass("O", 18)
    };

    public static IQueryable<SomeClass> MyTable {
        get {
            return _MyTable.AsQueryable();
        }
    }
}

public class SomeClass {
    public SomeClass(string property, int code) {
        this.SomeProperty = property;
        this.Code = code;
    }

    public string SomeProperty { get; set; }

    public int Code { get; set; }
}

LINQPad での実行結果

于 2012-09-19T20:53:55.383 に答える
0

通常、これを行います。

.OrderBy(x => x.yourField)

また

.OrderByDescending(x => x.yourField)

フィールドを動的にする必要がある場合は、この回答を確認してください

于 2012-09-19T08:43:27.263 に答える
0

stringフィールドが(たとえばを使用する場合)として渡される場合、 :ObjectDataSourceを使用してフィールドをマップできます。switch

var qry = context
  .MyTable
  .Where(x => x.Code > 5);

switch(orderBy) {
  case "MyField": qry = qry.OrderBy(r => r.MyField); break;
  case "MyField DESC": qry = qry.OrderByDescending(r => r.MyField); break;
}

// By the way, ToList can infer the generic type if you don't
// want to state it explicity
var result = qry.Skip(10).Take(5).ToList();

クエリはの前に実行されませんToList。少なくともEFを使用すると、SQLServerで実行されます。switchボイラープレートがかなり多いことは認めますが、非常に信頼性が高く、高速であることがわかりました。

于 2012-09-19T08:44:57.993 に答える