用于创建具有内部Collection的谓词的动态查询

我正在为我的MVC EF应用程序创建搜索function。 我正在使用动态查询创建它。 并遵循此方法https://www.codeproject.com/Articles/493917/Dynamic-Querying-with-LINQ-to-Entities-and-Express

它用于为实体的boolstring字段创建谓词。 我的应用程序中的主要实体是Applicant

EDMX Applicant正在关注

  public partial class Applicant { public Applicant() { this.ApplicantEducations = new HashSet(); this.ApplicantSkills = new HashSet(); this.Applications = new HashSet(); this.Experiences = new HashSet(); } public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } public byte[] CV_Upload1 { get; set; } public string CV_Upload2 { get; set; } public string email { get; set; } public string password { get; set; } public Nullable DOB { get; set; } virtual ICollection ApplicantEducations { get; set; } virtual ICollection ApplicantSkills { get; set; } virtual ICollection Applications { get; set; } virtual ICollection Experiences { get; set; } } 

我想搜索,即在申请人类型学院的教育中提交的机构名称。 申请人可以拥有一个或多个ApplicantEducations对象。

以下是我的申请人教育的EDMX课程

  public partial class ApplicantEducation { public int id { get; set; } public Nullable ApplicantId { get; set; } public Nullable InstituteId { get; set; } public Nullable EducationLevelId { get; set; } public Nullable IsComplete { get; set; } public Nullable DateStart { get; set; } public Nullable DateEnd { get; set; } public Nullable GPA { get; set; } public virtual EducationLevel EducationLevel { get; set; } public virtual Institute Institute { get; set; } public virtual Applicant Applicant { get; set; } } 

我的学院实体课就是这样的

 public class Institute { public int Id { get; set; } public string Name { get; set; } } 

因此,用户将通过指定学院名称进行搜索,所有申请人将通过该学院的教育进行检索。

正如我上面提到的链接。 下面举例说明字符串字段谓词构建

  private static Expression<Func> ApplyStringCriterion(TSearchCriteria searchCriteria, PropertyInfo searchCriterionPropertyInfo, Type dbType, MemberInfo dbFieldMemberInfo, Expression<Func> predicate) { // Check if a search criterion was provided var searchString = searchCriterionPropertyInfo.GetValue(searchCriteria) as string; if (string.IsNullOrWhiteSpace(searchString)) { return predicate; } // Then "and" it to the predicate. // eg predicate = predicate.And(x => x.firstName.Contains(searchCriterion.FirstName)); ... // Create an "x" as TDbType var dbTypeParameter = Expression.Parameter(dbType, @"x"); // Get at x.firstName var dbFieldMember = Expression.MakeMemberAccess(dbTypeParameter, dbFieldMemberInfo); // Create the criterion as a constant var criterionConstant = new Expression[] { Expression.Constant(searchString) }; // Create the MethodCallExpression like x.firstName.Contains(criterion) var containsCall = Expression.Call(dbFieldMember, StringContainsMethod, criterionConstant); // Create a lambda like x => x.firstName.Contains(criterion) var lambda = Expression.Lambda(containsCall, dbTypeParameter) as Expression<Func>; // Apply! return predicate.And(lambda); } 

上面的代码用于构建主实体类(申请人)中包含的简单字符串字段的谓词。 但申请人也有ApplicantEducation集合,所以我的问题是如何为linq where子句(方法)创建动态查询(谓词),因此当用户搜索学院名称时,所有申请人都将获得相同的教育。

我的搜索条件如下,

  public class SearchCriteriaVM { public int Id { get; set; } public string Name { get; set; } public DateTime? DOB { get; set; } public string Description { get; set; } public ICollection ApplicantEducations { get; set; } public ICollection Experiences { get; set; } public ICollection ApplicantSkills { get; set; } public ICollection Applications { get; set; } } 

我有点失落,这怎么可能。

谢谢

您可以使用以下方法在Lambda表达式中创建Dynamic Where子句

 public ActionResult GetRecords(int? classId, string name, bool isAll = false) { var allRecords = repository.Students; if (!isAll) { //Retrieve active records only allRecords = allRecords.Where(m => m.StatusId == 1); } if (!string.IsNullOrEmpty(name)) { allRecords = allRecords.Where(m => m.Name.StartsWith(name)); } if (classId.HasValue) { allRecords = allRecords.Where(m => m.ClassId == classId); } // other stuff } 

类似地,可以应用以下方法,以便仅检索以“query”参数值开头的记录,并在“query”参数值为null时检索所有记录:

 IQueryable students = repository.Students.Select(m => new StudentViewModel { Id = m.Id, Name = m.Name + " " + m.Surname }); if (!string.IsNullOrEmpty(query)) { students = students.Where(m => m.Name.StartsWith(query)); } 

或者“表现不佳”的另一种方式:

 .Where(m => string.IsNullOrEmpty(query) || m.Name.StartsWith(query)); 

希望这可以帮助…

在您的情况下,我们需要的基本操作是使用EF的动态查询构建器。 即一种基本的“匹配”方法,它包含作为IQueryable格式的数据,搜索术语以及用于过滤记录的属性。 “ 匹配 ”方法是我们需要在代码中使用的方法。

  public static IQueryable Match( IQueryable data, string searchTerm, IEnumerable>> filterProperties) { var predicates = filterProperties.Select(selector => selector.Compose(value => value != null && value.Contains(searchTerm))); var filter = predicates.Aggregate( PredicateBuilder.False(), (aggregate, next) => aggregate.Or(next)); return data.Where(filter); } 

要构建此表达式方法,我们需要一个Compose方法,以便它可以接受需要搜索的参数。

 public static Expression> Compose( this Expression> first, Expression> second) { var param = Expression.Parameter(typeof(TFirstParam), "param"); var newFirst = first.Body.Replace(first.Parameters[0], param); var newSecond = second.Body.Replace(second.Parameters[0], newFirst); return Expression.Lambda>(newSecond, param); } 

这将组成并返回一个lambda表达式,但要构建此方法,我们需要“ 替换 ”扩展方法。 顾名思义,此方法将一个表达式的所有实例替换为另一个表达式。

 public static Expression Replace(this Expression expression, Expression searchEx, Expression replaceEx) { return new ReplaceVisitor(searchEx, replaceEx).Visit(expression); } internal class ReplaceVisitor : ExpressionVisitor { private readonly Expression from, to; public ReplaceVisitor(Expression from, Expression to) { this.from = from; this.to = to; } public override Expression Visit(Expression node) { return node == from ? to : base.Visit(node); } } 

回到实际的“匹配”方法,我们需要一个谓词构建器,它将帮助我们呈现与搜索相关的AND,OR查询。

因此,谓词构建器将如下所示:

  public static class PredicateBuilder { public static Expression> True() { return f => true; } public static Expression> False() { return f => false; } public static Expression> Or( this Expression> expr1, Expression> expr2) { var secondBody = expr2.Body.Replace( expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda> (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters); } public static Expression> And( this Expression> expr1, Expression> expr2) { var secondBody = expr2.Body.Replace( expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda> (Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters); } } 

因此,我们需要的是匹配方法,然后根据您的要求运行。

根据您的模型结构,如果您需要任何进一步的帮助,请告诉我。