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

时间:2016-07-11 13:23:06

标签: .net entity-framework linq generics linq-to-sql

我有以下问题,我的头脑缠绕了好几个小时:

我想要过滤几个实体。 它们都有一个共同的 Person 类型的导航属性 - 虽然它在所有这些实体中都没有被称为相同。

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扩展,它可以在任何Entity-Collection上使用,并获取导航属性的路径和一些静态过滤器参数。由于我查询的实体没有公共基础,因此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));            
    }

这里显而易见的问题是我没有物业&#34; ContractCreator&#34;在类型T的通用上下文中。

现在的问题是:我如何转换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));            
    }

为了完整性&#39;为了更好地理解,这里是我称之为扩展的方式:

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

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

我非常期待你的回答!

1 个答案:

答案 0 :(得分:1)

您可以使用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));            
}