我正在尝试创建Linq to SQL表达式,以便通常允许在两个不同的域实体记录上比较相同的属性。一般的想法是定义实体上需要比较哪些属性,然后逐个比较每个属性以检查相等/不等式。我通过在域实体上创建表达式来识别需要比较哪些属性:
public class CompareEntityProperty<TEntity> where TEntity : IEntity
{
public Expression<Func<TEntity, object>> EntityPropertyExpression { get; set; }
public Expression<Func<TEntity, TEntity, bool>> Compare
{
get
{
var expression = EntityPropertyExpression;
return (entityA, entityB) => object.Equals(expression.Invoke(entityA), expression.Invoke(entityB));
}
}
}
然后为通用实体设置它,我会这样设置:
public class foo : IEntity
{
public long? bar { get; set; }
}
我会使用以下方式进行设置:
public class fooCompare
{
public IEnumerable<CompareEntityProperty<foo>> CompareList
{
get
{
return new []
{
new CompareEntityProperty<foo>() { EntityPropertyExpression = entity => entity.bar }
};
}
}
}
我看到的问题似乎与使用'object'作为属性类型设置我的属性表达式有关。当表达式被编译时,它会尝试将属性类型(在这种情况下是一个可空的long)转换为一个对象,哪个SQL不知道该怎么做,我得到一个错误,如:
无法将类型'System.Nullable`1 [[System.Int64,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]'强制转换为'System.Object'。
当我添加一个手表并查看实际生成的表达式时,这似乎得到了证实:
entity =&gt;转换(entity.bar)
看起来它试图首先将属性值转换为'对象'类型可以使用的类型,因此错误。
首先,我对错误的假设是否正确?有没有解决的办法?有没有办法将属性表达式设置为动态而不是强类型为“对象”?还是有其他选择可以解决这个问题吗?
谢谢!
编辑:我正在使用LinqKit库,它提供了处理要转换为SQL的表达式上的'Invoke'方法调用所必需的逻辑。
答案 0 :(得分:0)
我不确定您使用哪个库来使您的当前代码适合您,但如果您想手动生成表达式,则需要:
从您的EntityPropertyExpression
中抓取Body
entity.Bar
创建一个新的ParameterExpression来表示你的第二个lambda参数。
使用表达式树访问者创建一个新表达式,用新参数的实例替换lambda参数的实例
entity2.Bar
使用Expression.Call()
生成对Equals
方法的方法调用,传入两个成员表达式
object.Equals(entity.Bar, entity2.Bar)
使用Expression.AndAlso()
将任意数量的表达式树组合在一起:
object.Equals(entity.Foo, entity2.Foo) &&
object.Equals(entity.Bar, entity2.Bar) &&
object.Equals(entity.Baz, entity2.Baz)
使用Expression.Lambda<>()
生成一个新的lambda表达式,该表达式接受两个参数并将它们应用于您构建的表达式:
(entity, entity2) =>
object.Equals(entity.Foo, entity2.Foo) &&
object.Equals(entity.Bar, entity2.Bar) &&
object.Equals(entity.Baz, entity2.Baz)
如果实体框架或LINQ to SQL在将值转换为object
以传递到object.Equals()
的概念方面存在问题,您可能需要在上面的步骤4中使用反射来查找适当的.Equals()
实例方法并调用它。