静态表达式作为动态linq查询的实例属性

时间:2017-04-10 17:08:35

标签: c# linq expression expression-trees linqkit

我使用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的所有可见条目。

我想知道是否有办法没有这个静态属性。这样,我就可以Interfaces使用IVisibilityEntity来强制使用特定类型的公共IsVisible属性。

现在我最终得到了:

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

但这会引发异常

  

InvalidOperationException:变量&#39; m&#39;类型&#39; tblMain&#39;引用范围&#39;&#39;,但未定义。

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

我希望拥有的是像

这样的查询
var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => m.IsVisible.Invoke())
    .ToList();

这似乎没有那么大的变化。但我真的希望能够使用interface-feature来描述我的底层数据库模型。

使用接口,它还允许检查,例如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>'

1 个答案:

答案 0 :(得分:0)

如何定义您的属性如下: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包来解析。