【问题标题】:Linq to SQL Domain Entity Property Comparison Using Expressions使用表达式比较 Linq to SQL 域实体属性
【发布时间】:2015-08-07 20:26:07
【问题描述】:

我正在尝试创建 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 }
                };
        }
    }
}

我看到的问题似乎与如何使用“对象”作为属性类型来设置属性表达式有关。编译表达式时,它会尝试将属性类型(在本例中为可为空的 long 类型)转换为对象,SQL 不知道该怎么做,我收到如下错误:

无法将类型“System.Nullable`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]”转换为类型“System.Object”。

当我添加手表并查看实际生成的表达式时,这似乎得到了证实:

entity => 转换(entity.bar)

看起来它正在尝试首先将属性值转换为“对象”类型可以使用的类型,因此出现错误。

首先,我对错误的假设是否正确?有没有解决的办法?有没有办法将属性表达式设置为动态而不是强类型为“对象”?还是有其他方法可以绕过这个问题?

谢谢!

编辑:我正在使用 LinqKit 库,它提供了处理要转换为 SQL 的表达式上的“Invoke”方法调用所需的逻辑。

【问题讨论】:

  • expression.Invoke(entityA) 无法编译,因为Expression.Invoke() 将表达式作为参数。您是否使用了某种第三方库的扩展方法之类的?
  • 是的,你是对的。我正在使用 LinqKit 库,它为这些类型的调用提供了功能。

标签: c# sql linq entity-framework


【解决方案1】:

我不确定您使用什么库来使当前代码为您工作,但如果您想手动生成表达式,您将需要:

  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&lt;&gt;() 生成一个新的 lambda 表达式,该表达式接受两个参数并将它们应用于您构建的表达式:

    (entity, entity2) => 
        object.Equals(entity.Foo, entity2.Foo) &&
        object.Equals(entity.Bar, entity2.Bar) &&
        object.Equals(entity.Baz, entity2.Baz)
    

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多