首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用EntityFramework和LinqKit查询接口属性

使用EntityFramework和LinqKit查询接口属性
EN

Stack Overflow用户
提问于 2014-01-22 00:45:07
回答 1查看 546关注 0票数 2

我使用EntityFramework和LinqKit来构建表达式树,并将其转换为SQL。我们还使用规范模式来组织我们的查询。

我们几乎所有的域对象都需要通过描述来执行查询,但在其中一些类中,该属性称为"Name",在其他类中称为" description ",等等。

因此,最初定义的接口如下:

代码语言:javascript
复制
public interface IDescritible
{
    string Description { get; }
}

当我尝试在一个类中显式实现它并对其进行泛型查询时,问题出现了:

代码语言:javascript
复制
public class Foo : IDescritible
{
    public string Name { get; set; }

    string IDescritible.Description
    {
        get { return this.Name; }
    }
}

public class DescriptionMatch<T> : AbstractSpecification<T> 
    where T : IDescritible
{
    public string Query { get; set; }

    public DescriptionMatch(string query)
    {
        this.Query = query;
    }

    public override Expression<Func<T, bool>> IsSatisfiedBy()
    {
        return x => x.Description.Contains(Query);
    }
}

运行时,EntityFramework无法将属性get (方法调用)转换为SQL表达式。

然后,我尝试在类中定义一个表达式,如下所示:

代码语言:javascript
复制
public interface IDescritible<T> where T: IDescritible<T>
{
    Expression<Func<T, string>> DescriptionExpression { get; }
}

public class Foo : IDescritible<Foo>
{
    public string Name { get; set; }

    public Expression<Func<Foo, string>> DescriptionExpression
    {
        get { return x => x.Name; }
    }
}

public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>
{
    public string Query { get; set; }

    public DescriptionMatch(string query)
    {
        this.Query = query;
    }

    public override Expression<Func<T, bool>> IsSatisfiedBy()
    {
        Expression<Func<T, bool>> combinedExpression = x => x.DescriptionExpression.Invoke(x).Contains(this.Query);
        return combinedExpression.Expand();
    }
}

但是当它执行.Expand()时会抛出异常:无法将'System.Linq.Expressions.PropertyExpression‘类型的对象强制转换为'System.Linq.Expressions.LambdaExpression’类型。

然后,我发现LinqKit只支持扩展本地定义的表达式(如this question所述),并且有一些非官方的代码编写来解决这些问题(在this question上回答)。

但是,当我修改LinqKit库以尝试第二个问题中提出的解决方案之一时,它开始抛出:从作用域'‘引用的'Foo’类型的变量'x‘,但它没有定义。

也许这是因为我还没有Foo的实例?只得到了泛型类型参数,这就是为什么我不能在局部变量上定义表达式的原因。也许有一种方法可以定义为静态表达式,以某种方式“附加”到类中?但这样我就不能在通用查询中使用它了,没有接口...

有没有一种方法可以修改LinqKit,这样我就可以构建在接口的显式实现上定义的表达式?或者还有另一种方法可以对显式实现的属性进行泛型查询?或任何其他解决方案或事情要考虑的?

这不需要使用LinqKit或规范模式,但EntityFramework是强制性的,重要的是要有一个接口/任何其他方式来支持“指出”哪个属性是description属性,并在此基础上进行泛型表达。

提前谢谢你!

EN

回答 1

Stack Overflow用户

发布于 2015-01-15 02:45:55

最简单的方法是进行以下更改

代码语言:javascript
复制
public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>, new()

然后,您可以通过简单地创建一个T(它是EF),使用表达式并以其他方式丢弃对象来获得一个实例

代码语言:javascript
复制
public interface IDescritible<T> where T : IDescritible<T>
{
    Expression<Func<T, string>> DescriptionExpression { get; }
}

public class Foo : IDescritible<Foo>
{
    public string Name { get; set; }

    public Expression<Func<Foo, string>> DescriptionExpression
    {
        get { return x => x.Name; }
    }
}

public abstract class AbstractSpecification<T>
{
    public abstract Expression<Func<T, bool>> IsSatisfiedBy();
}

public class DescriptionMatch<T> : AbstractSpecification<T> 
    where T : IDescritible<T>, new()
{
    public string Query { get; set; }

    public DescriptionMatch(string query)
    {
        this.Query = query;
    }

    public override Expression<Func<T, bool>> IsSatisfiedBy()
    {
        Expression<Func<T, string>> lambda = new T().DescriptionExpression;
        return Expression.Lambda<Func<T, bool>>(
            Expression.Call(
                lambda.Body,
                "Contains",
                Type.EmptyTypes,
                Expression.Constant(
                    this.Query,
                    typeof(string)
                )
            ),
            lambda.Parameters
        );
    }
}

public class ExpressionReplacer : ExpressionVisitor
{
    private readonly Expression _toBeReplaced;
    private readonly Expression _replacement;

    public ExpressionReplacer(Expression toBeReplaced, Expression replacement)
    {
        if (toBeReplaced.Type != replacement.Type)
        {
            throw new ArgumentException();
        }
        this._toBeReplaced = toBeReplaced;
        this._replacement = replacement;
    }

    public override Expression Visit(Expression node)
    {
        return Object.ReferenceEquals(node, this._toBeReplaced) ? this._replacement : base.Visit(node);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21264130

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档