C# EF/LINQ:Where()针对子类型的属性
我有一套POCO,它们都实现了以下简单接口:C# EF/LINQ:Where()针对子类型的属性,c#,linq,entity-framework,linq-to-entities,covariance,C#,Linq,Entity Framework,Linq To Entities,Covariance,我有一套POCO,它们都实现了以下简单接口: interface IIdObject { int Id { get; set; } } interface IDeletableObject : IIdObject { bool IsDeleted { get; set; } } 这些POCO的一个子集实现此附加接口: interface IIdObject { int Id { get; set; } } interface IDeleta
interface IIdObject
{
int Id { get; set; }
}
interface IDeletableObject : IIdObject
{
bool IsDeleted { get; set; }
}
这些POCO的一个子集实现此附加接口:
interface IIdObject
{
int Id { get; set; }
}
interface IDeletableObject : IIdObject
{
bool IsDeleted { get; set; }
}
我的存储库层次结构如下所示:
public override IQueryable<T> Query()
{
return base.Query().Where(t => ((IDeletableObject)t).IsDeleted == false);
}
i假设这太大了,无法评论,所以 您可以动态创建表达式。我创建了帮助器方法:
public static class ExpressionHelper
{
public static MemberExpression PropertyExpression(this Expression expr,string propertyName)
{
var properties = propertyName.Split('.');
MemberExpression expression = null;
foreach (var property in properties)
{
if (expression == null)
expression = Expression.Property(expr, property);
else
expression = Expression.Property(expression, property);
}
return expression;
}
public static BinaryExpression EqualExpression<T>(this Expression expr, string propertyName, T value)
{
return Expression.Equal(expr.PropertyExpression(propertyName), Expression.Constant(value, typeof(T)));
}
}
公共静态类ExpressionHelper
{
公共静态MemberExpression PropertyExpression(此表达式expr,字符串propertyName)
{
var properties=propertyName.Split('.');
MemberExpression=null;
foreach(属性中的var属性)
{
if(表达式==null)
expression=expression.Property(expr,Property);
其他的
expression=expression.Property(表达式,属性);
}
返回表达式;
}
公共静态二进制表达式EqualExpression(此表达式expr,字符串propertyName,T值)
{
返回Expression.Equal(expr.PropertyExpression(propertyName),Expression.Constant(value,typeof(T));
}
}
然后您可以使用:
//Checking if T implements IDeletableObject
if (typeof(IDeletableObject).IsAssignableFrom(typeof(T)))
{
//a
var parameter = Expression.Parameter(typeof(T), "a");
//a.IsDeleted == false
var where = parameter.EqualExpression("IsDeleted", false);
//a => a.IsDeleted == false
var condition = Expression.Lambda<Func<T, bool>>(where, parameter);
list = list.Where(condition);
}
//检查T是否实现了IDeletableObject
if(typeof(IDeletableObject).IsAssignableFrom(typeof(T)))
{
//a
var参数=表达式参数(类型为(T),“a”);
//a、 IsDeleted==false
var,其中=参数.EqualExpression(“IsDeleted”,false);
//a=>a.IsDeleted==false
var条件=表达式.Lambda(其中,参数);
列表=列表。其中(条件);
}
编辑
您也可以使用。它也使用表达式,但并不强迫您考虑它是如何工作的,只需将简单的条件写成字符串即可。我不知道它是如何处理布尔值的。对此,必须使用非接口类型。EF不知道如何将接口实现转换为SQL。您不能将
where t:IDeletableObject
应用于类型参数吗?从Repository
继承并使用附加的类型约束创建DeletableRepository
。@Craig:如果我使用类,我很不幸会遇到多个继承问题:-(@LukLed:现在我的IoC容器中有一条创建存储库的规则。我相信创建新的存储库类型(或重新参数化它们)将需要额外的规范,这是我希望避免的。非常有趣(我非常感谢您的帮助,呵呵)。我会尽快试用!@ladenedge:它应该可以正常工作,但可能需要一些调整。我无法完全测试它。嗯,我在这里对您的代码进行了一些测试,但是动态Linq太简单了,呵呵。生成的代码看起来像:set.Where(“IsDeleted=@0”,false)
-非常简单!非常感谢您的时间和帮助!@ladenedge:先玩一会儿,然后使用动态linq可能是最好的解决方案:)