【问题标题】:Static expression as instance-property for dynamic linq-queries静态表达式作为动态 linq 查询的实例属性
【发布时间】:2017-09-05 20:21:39
【问题描述】:

我正在使用 LinqKit 的修改版本,以便将我的扩展程序放在一个地方。

因此,我在每个实体类中都有一个单独的部分来定义我的表达式,例如对于tblMain

public partial class tblMain
{
    public static Expression<Func<tblMain, bool>> IsVisible => (e) => e.MainStatus == "Visible";
}

在查询中我现在可以写这样的东西

var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => tblMain.IsVisible.Invoke(m))
    .ToList();

这将返回表 tblMain 的所有可见条目。

我想知道是否有任何方法可以不让这个静态属性。这将使我能够像IVisibilityEntity 一样使用Interfaces 来强制特定类型上的公共IsVisible 属性。

现在我已经结束了:

public Expression<Func<bool>> IsVisible2 => Expression.Lambda<Func<bool>>(Expression.Invoke(IsVisible, Expression.Variable(typeof(tblMain))));

但这给我抛出了一个异常

InvalidOperationException:从范围“”引用了“tblMain”类型的变量“m”,但未定义。

使用Expression.Constant(this, typeof(tblMain)) 作为第二个参数时相同。

我想要的是这样的查询

var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => m.IsVisible.Invoke())
    .ToList();

这似乎没有太大的变化。但我真的希望能够使用接口功能来描述我的底层数据库模型。

通过接口,它还允许检查,例如if(myEntity is IVisibilityEntity) 做特定的可见性。

如果可以,有什么想法以及如何实现?

编辑 1

截至第一条评论。我使用LinqKit 为子查询启用相同的逻辑:

var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => tblMain.IsVisible.Invoke(m))
    .Select(m => new
    {
        VisibleSubs = m.tblSub.Where(s => tblSub.IsVisible.Invoke(s)).Select(s => new 
        {
            // ...
        })
    })
    .ToList();

上面的查询将为我提供所有可见的主条目及其相关(以及可见的)子条目。但这只是简单地写m.tblSub.Where(tblSub.IsVisible) 是不可能的,如下所示

CS1929 'ICollection<tblSub>' does not contain a definition for 'Where' and the best extension method overload 'Queryable.Where<tblSub>(IQueryable<tblSub>, Expression<Func<tblSub, bool>>)' requires a receiver of type 'IQueryable<tblSub>'

【问题讨论】:

  • 在你的第一个 sn-p 中你可以写 .Where(tblMain.IsVisible) 然后你甚至根本不需要 LINQKit。
  • @Servy 我知道这种用法。请参阅我更新的问题 (Edit 1)。此解决方案也不能解决接口问题,也不适合子查询。

标签: c# linq expression expression-trees linqkit


【解决方案1】:

像这样定义你的属性怎么样:https://damieng.com/blog/2009/06/24/client-side-properties-and-any-remote-linq-provider 它本质上是以下形式的属性定义:

partial class Employee {
    private static readonly CompiledExpression<Employee,string> fullNameExpression
     = DefaultTranslationOf<Employee>.Property(e => e.FullName).Is(e => e.Forename + " " + e.Surname);
    private static readonly CompiledExpression<Employee,int> ageExpression
     = DefaultTranslationOf<Employee>.Property(e => e.Age).Is(e => DateTime.Now.Year - e.BirthDate.Value.Year - (((DateTime.Now.Month < e.BirthDate.Value.Month) || (DateTime.Now.Month == e.BirthDate.Value.Month && DateTime.Now.Day < e.BirthDate.Value.Day)) ? 1 : 0)));

  public string FullName {
    get { return fullNameExpression.Evaluate(this); }
  }

  public int Age {
    get { return ageExpression.Evaluate(this); }
  }
}

并使用 Microsoft.Linq.Translations 包来解决。

【讨论】:

    猜你喜欢
    • 2016-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多