Linq to SQL Domain Entity使用表达式进行属性比较

时间:2015-08-07 20:26:07

标签: c# sql linq entity-framework

我正在尝试创建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'方法调用所必需的逻辑。

1 个答案:

答案 0 :(得分:0)

我不确定您使用哪个库来使您的当前代码适合您,但如果您想手动生成表达式,则需要:

  1. 从您的EntityPropertyExpression

    中抓取Body
    entity.Bar
    
  2. 创建一个新的ParameterExpression来表示你的第二个lambda参数。

  3. 使用表达式树访问者创建一个新表达式,用新参数的实例替换lambda参数的实例

    entity2.Bar
    
  4. 使用Expression.Call()生成对Equals方法的方法调用,传入两个成员表达式

    object.Equals(entity.Bar, entity2.Bar)
    
  5. 使用Expression.AndAlso()将任意数量的表达式树组合在一起:

    object.Equals(entity.Foo, entity2.Foo) &&
    object.Equals(entity.Bar, entity2.Bar) &&
    object.Equals(entity.Baz, entity2.Baz)
    
  6. 使用Expression.Lambda<>()生成一个新的lambda表达式,该表达式接受两个参数并将它们应用于您构建的表达式:

    (entity, entity2) => 
        object.Equals(entity.Foo, entity2.Foo) &&
        object.Equals(entity.Bar, entity2.Bar) &&
        object.Equals(entity.Baz, entity2.Baz)
    
  7. 如果实体框架或LINQ to SQL在将值转换为object以传递到object.Equals()的概念方面存在问题,您可能需要在上面的步骤4中使用反射来查找适当的.Equals()实例方法并调用它。