动态导航的通用 LINQ 扩展 属性

Generic LINQ Extension on dynamic Navigation property

我有以下问题,几个小时都无法解决问题:

我有几个要过滤的实体。 它们都有一个共同的 Person 类型的 Navigation 属性 - 尽管在所有这些实体中它的名称并不相同。

Person 实体有一个 CompanyRelation 实例列表,其中说明了 Relation 必须是公司

public class Person
{
   public Collection<CompanyRelation> CompanyRelations { get; set; }
}

public enum CompanyRelationType
{
    Employee,
    Manager
}

public class Contract
{
    public Person ContractCreator { get; set; }
}

public class CompanyRelation
{
    public virtual Guid PersonId { get; set; }

    public virtual Person Person { get; set; }

    public virtual Guid CompanyId { get; set; }

    public virtual Company Company { get; set; }

    public virtual CompanyRelationType RelationType { get; set; }
}

我现在想编写一个通用的 LINQ 扩展,它可以用于任何实体集合并采用导航路径 属性 和一些静态过滤器参数。由于我查询的实体没有共同的基础,因此 LINQ 扩展在类型 T 上是通用的。

到目前为止,我想到了这样的事情:

    public static IQueryable<T> HasRelation<T>(this IQueryable<T> query, Expression<Func<T, Person>> personExpr, Guid companyId, CompanyRelationType relationType)
    {
        return query = query.Where(tc => tc.ContractCreator.CompanyRelations.Any(cr => cr.CompanyId == companyId));            
    }

这里明显的问题是我在类型 T 的通用上下文中没有 属性 "ContractCreator"。

现在的问题是:如何将我在其中定义导航路径 属性 的 personExpr 转换为一种形式,我可以在其上编写过滤器查询并且仍然可以使用 LINQ to SQL.

我也试过它作为 lambda,我用 tc 调用它,但是由于 LINQ to SQL 不支持调用,所以也没有用:

    public static IQueryable<T> HasRelation<T>(this IQueryable<T> query, Func<T, Person> personExpr, Guid companyId, CompanyRelationType relationType)
    {
        return query = query.Where(tc => personExpr(tc).CompanyRelations.Any(cr => cr.CompanyId == companyId));            
    }

为了完整起见,也可能是为了更好地理解,这里是我调用扩展名的方式:

Guid companyId = ... //Some Company's Id

var result = this.unitOfWork.Contracts      .HasAnyRelation(c => c.ContractCreator, companyId, CompanyRelationType.Employee);

非常期待您的回答!

您可以像这样使用 LinqKit AsExpandableInvoke 扩展方法:

public static IQueryable<T> HasRelation<T>(this IQueryable<T> query, Expression<Func<T, Person>> personExpr, Guid companyId, CompanyRelationType relationType)
{
    return query.AsExpandable().Where(tc => 
        personExpr.Invoke(tc).CompanyRelations.Any(cr => cr.CompanyId == companyId));            
}