如何在扩展方法中键入是否存在属性?

时间:2013-05-24 08:39:25

标签: c# linq extension-methods

我经常有这样的代码:

var stRecs = db.<someTable>
             .Where(a => a.DepID == depID)

选择单个记录,但如果depID == 0我想取回所有记录。

我正在考虑创建一个扩展方法“WhereDepID_OrAll”,比如

public static IQueryable<T> WhereDepID_OrAll<T>(this IQueryable<T> source)
        where T: // is what?
{
    if(depID > 0) { return source.Where(a => a.depID == depID); }
    else return source.Where(a => a);
}

现在我的基本问题是: 我有几个带depID的表 - 如何设置Where T:
该方法将如何确定表是否具有depID?

解决潜在问题的更好方法?

5 个答案:

答案 0 :(得分:6)

乍一看,反应将是:创建一个界面

public interface ObjectWithDepartmentInterface {
    int depID;
}

使用此depId实现此接口的所有实体,并使用

where T : ObjectWithDepartmentInterface

但linq to entities不接受查询中接口的属性...例如:Expression generated based on interface

因此,唯一的方法是使用depId从具有depId属性的公共实体(可能是抽象)继承depId。

并使用此抽象实体作为

where T:

更简单(但更丑陋的方法)可能是不在T上添加约束,在方法中构建谓词,并在不良情况下抛出异常。

if (typeof(T).GetProperty("depId") == null)
   throw InvalidOperationException (string.Format("{0}" doesn't have a depId property, typeof(T).Name))

修改

但也许这不是depId作为共同财产的问题 然后

public static IQueryable<T> WhereExistsOrAll<T>(this IQueryable<T> source, string propertyName, int value)
        where T: // is what?
{
    if (value == 0)
    return source;
    var parameter = Expression.Parameter(typeof(T), "m");
    Expression member = parameter;
    member = Expression.Property(member, propertyName);
    member = Expression.Equals(member, Expression.Constant(value));
    var lambda = Expression.Lambda<Func<T, bool>>(member, new[]{parameter});
    return source.Where(lambda);
}

使用

var stRecs = db.<someTable>.WhereExistsOrAll("depId", depId);

编辑2

另一种方法是解析Predicate以获得“常量”值

类似的东西

public static IQueryable<T> GetAllOrRestrict<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate)
{
       var expression = predicate.Body as BinaryExpression;

       var rightPart = expression.Right as MemberExpression;
       var value = GetValue(rightPart);
       var test = value.ToString();
       int val;
       if (Int32.TryParse(value.ToString(), out val))
       {
           if (val != 0)
               return queryable.Where(predicate);
       }

       return queryable;
}

private static object GetValue(MemberExpression member)
{
     var objectMember = Expression.Convert(member, typeof(object));
     var getterLambda = Expression.Lambda<Func<object>>(objectMember);
     var getter = getterLambda.Compile();
     return getter();
}

使用

var stRecs = db.<someTable>.GetAllOrRestrict(m => m.depID == depId);

答案 1 :(得分:2)

我知道这不是特别时髦,但这不正是the Query Builder methods in Entity Framework的用途吗?

var stRecs = db.<someTable>
             .Where("it.DepID == @depID OR @depID = 0", 
                    new ObjectParameter("depID", depID));

这适用于任何someTable,因此它有一个名为DepID的列。它当然可以成为一种扩展方法:

public static ObjectQuery<T> WhereIdEqualOrAll<T>(this ObjectQuery<T> q, int depID)
    where T : class
{
    return q.Where("it.DepID = @id OR @id = 0", new ObjectParameter("id", id));
}

因此被调用:

var stRecs = db.<someTable>.WhereIdEqualOrAll(depID);

答案 2 :(得分:1)

使用界面:

public interface IInterface
{
   int depId;
}

这将迫使T继承IInterface并实施depId

然后您可以将其添加到扩展程序:

public static IQueryable<T> WhereDepID_OrAll<T>(this IQueryable<T> source) where T: IInterface
{

}

答案 3 :(得分:0)

使用界面,然后手动构建表达式树,引用实际的类。

答案 4 :(得分:0)

Raphaels Edit 2完成了这项工作!

小版本: 如果存在DepID,我怎么能包含NULL值?

我想返回ID == x OR ID == NULL

的所有部门

可能还有额外的bool includeNullValues)

public static IQueryable<T> GetAllOrRestrict<T>(this IQueryable<T> queryable,
 Expression<Func<T, bool>> predicate, 
 bool includeNullValues)
    {
        var expression = predicate.Body as BinaryExpression;

        var rightPart = expression.Right as MemberExpression;
        var value = GetValue(rightPart);
        var test = value.ToString();
        int val;
        if (Int32.TryParse(value.ToString(), out val))
        {
            if (val != 0)
            {
                if (includeNullValues)
                {
                    var parameter = Expression.Parameter(typeof(T),"m");

                    return queryable.Where(predicate) <====HOW to " || depID == null) ???
                }
                else
                {
                return queryable.Where(predicate);
                }
            }
        }

        return queryable;
    }