3

いくつかのパラメーターに基づいてさまざまなクエリを動的に生成する関数を作成しようとしています。LINQ構文について少し混乱していて、正しく実行しているかどうかわかりません。

文字列タイプのパラメータのセットは、「search」(検索テキストボックス値の場合)、「searchfield」(検索対象)、「limit_begin」、「limit_end」で、行数と開始場所を示します。注文するフィールドの「order_by」。並べ替える方法の「order_sort」。

以前、stackoverflowでこの「getpropertyvalue」リフレクション関数を見つけました。私自身の解釈に基づいて、意図したとおりに機能することを期待しています。

 private static object GetPropertyValue(object obj, string property)
    {
        System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
        return propertyInfo.GetValue(obj, null);
    }

if (order_sort == "ASC")
        {
            (from a in entities.UserTable
             where GetPropertyValue(a, searchfield).ToString().Contains(search)
             select a)
                .OrderBy("a." + order_by)
                .Skip(Convert.ToInt32(limit_begin))
                .Take(Convert.ToInt32(limit_end))
                .ToList();
        }
        else if (order_sort == "DESC")
        {
            (from a in entities.UserTable
             where GetPropertyValue(a, searchfield).ToString().Contains(search)
             select a)
                .OrderByDescending("a." + order_by)
                .Skip(Convert.ToInt32(limit_begin))
                .Take(Convert.ToInt32(limit_end))
                .ToList();
        }

「Orderby」行でエラーが発生し、VS2008はそれを赤で強調表示して、引数のタイプを使用法から推測できないことを示しています。

4

3 に答える 3

5

.OrderByおよびメソッドにはタイプの.OrderByDescendingパラメーターが必要でありFunc<T, TKey>、文字列を渡します。基本的には、並べ替えるプロパティを識別するために使用できる式を要求します。最初に文字列を使用する必要があるため、OrderBy内でリフレクションを使用することをお勧めします。

.OrderBy(x => x.GetType().GetProperty(order_by).GetValue(x, null).ToString())

ご覧のとおり、これは読みやすいものではありませんが、うまくいくはずです。http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-でLINQ動的クエリライブラリを調べることもできます。 library.aspx

お役に立てれば!:)

于 2012-08-16T18:03:36.430 に答える
2

This is how I've dealt with this in the past. Notice is is a single column search and sort, which it sounds like what you are going for.

var users = entities.UserTable;

// Setup the default order column.
Func<SweetEntity, string> orderFunc = u => u.Field1;

switch (searchfield)
{
    case "Field1":
        orderFunc = u => u.Field1;
        users = users.Where(u => u.Field1.Contains(search));
        break;
    case "Field2":
        orderFunc = u => u.Field2;
        users = users.Where(u => u.Field2.Contains(search));
        break;
}

// If you need to get the total count, do it here:
var totalUserCount = users.Count();

// Apply sorting:
if (order_sort == "ASC")
{
    users = users.OrderBy(orderFunc);
}
else
{
    users = users.OrderByDescending(orderFunc);
}

// Apply paging:
users = users.Skip(Convert.ToInt32(limit_begin)).Take(Convert.ToInt32(limit_end));

I would do something other than Convert.ToInt32, such as int.TryParse, but for the example I didn't.

Edit 1:

If you end up wanting a more robust search, look into PredicateBuilder in LinqKit (http://www.albahari.com/nutshell/predicatebuilder.aspx).

Edit 2:

My example just does sting contains in the filtering portion. Of course you could customize all that logic for the specific filter the user is requesting. If they're filtering on an int, you'd convert the filter string to an int, then can just compare with == in the lambda expression. Something like:

int myId;
if (int.TryParse(search, out myId))
{
    users = users.Where(u => u.SomeIntegerField == myId);
}
于 2012-08-16T18:08:20.077 に答える
0

The subject of the original question is achievable easily with Expression Trees and reflection.

You can checkout a working example of adding strong type Sort \ Filter from just string column names and values to EF6 in a github repo I made for one of my talks

Here is a sample of sort functionality from the class in the link

 public class GridRequestSort
    {
        public string PropName { get; set; }
        public bool IsDescending { get; set; }
    }

        private static IQueryable<T> WrapSort<T>(
            IQueryable<T> query,
            GridRequestSort sort,
            bool isFirst = false)
        {
            var propAccessExpr = GetPropAccesssLambdaExpr(typeof(T), sort.PropName);
            var orderMethodName = "";
            if (isFirst)
            {
                orderMethodName = sort.IsDescending ? "OrderByDescending" : "OrderBy";
            } 
            else
            {
                orderMethodName = sort.IsDescending ? "ThenByDescending" : "ThenBy";
            }

            var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == orderMethodName && m.GetParameters().Length == 2);
            var genericMethod = method.MakeGenericMethod(typeof(T), propAccessExpr.ReturnType);
            var newQuery = (IQueryable<T>)genericMethod.Invoke(null, new object[] { query, propAccessExpr });
            return newQuery;
        }

        private static LambdaExpression GetPropAccesssLambdaExpr(Type type, string name)
        {
            var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            var param = Expression.Parameter(type);
            var propAccess = Expression.Property(param, prop.Name);
            var expr = Expression.Lambda(propAccess, param);
            return expr;
        }
于 2016-12-30T13:56:18.950 に答える