我经常有这样的代码:
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?
解决潜在问题的更好方法?
答案 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;
}