动态查询,用于使用内部Collection创建谓词 [英] Dynamic query for creating where predicate with inner Collection

查看:58
本文介绍了动态查询,用于使用内部Collection创建谓词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的MVC EF应用程序创建搜索功能.我正在使用动态查询创建它.然后按照此方法 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<ApplicantEducation>();
         this.ApplicantSkills = new HashSet<ApplicantSkill>();
         this.Applications = new HashSet<Application>();
         this.Experiences = new HashSet<Experience>();
        }

    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<System.DateTime> DOB { get; set; }

   virtual ICollection<ApplicantEducation> ApplicantEducations { get; set; }
   virtual ICollection<ApplicantSkill> ApplicantSkills { get; set; }
   virtual ICollection<Application> Applications { get; set; }
   virtual ICollection<Experience> Experiences { get; set; }
}

我要搜索,即使用在Institute类型的ApplicantEducations中提交的机构名称.申请人可以具有一个或多个ApplicantEducations对象.

以下是我的ApplicantEducations的EDMX课程

   public partial class ApplicantEducation
{
    public int id { get; set; }
    public Nullable<int> ApplicantId { get; set; }
    public Nullable<int> InstituteId { get; set; }
    public Nullable<int> EducationLevelId { get; set; }
    public Nullable<bool> IsComplete { get; set; }
    public Nullable<System.DateTime> DateStart { get; set; }
    public Nullable<System.DateTime> DateEnd { get; set; }
    public Nullable<short> GPA { get; set; }

    public virtual EducationLevel EducationLevel { get; set; }
    public virtual Institute Institute { get; set; }
    public virtual Applicant Applicant { get; set; }
}

我的Institute实体类是这样的

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

  }

因此,用户将通过指定机构名称进行搜索,所有申请人将从该机构接受教育.

正如我在上面提到的那样,链接.下面以字符串字段谓词构建为例进行演示

     private static Expression<Func<TDbType, bool>> ApplyStringCriterion<TDbType,
        TSearchCriteria>(TSearchCriteria searchCriteria, PropertyInfo searchCriterionPropertyInfo,
        Type dbType, MemberInfo dbFieldMemberInfo, Expression<Func<TDbType, bool>> 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.
        // e.g. 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<TDbType, bool>>;
        // Apply!
        return predicate.And(lambda);
    }

上面的代码为主Entity类(申请人)中包含的简单字符串字段构建谓词.但是,申请人还具有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<Models.ApplicantEducationVM> ApplicantEducations { get; set; }
    public ICollection<Models.ExperienceVM> Experiences { get; set; }
    public ICollection<Models.ApplicantSkillsVM> ApplicantSkills { get; set; }

    public ICollection<Models.ApplicationsVM> 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" 参数值的所有记录为空:

IQueryable<StudentViewModel> 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));

希望这对您有帮助...

I am creating search capability for my MVC EF application. I am creating it using dynamic query. And following this method https://www.codeproject.com/Articles/493917/Dynamic-Querying-with-LINQ-to-Entities-and-Express

Its for creating predicate for bool and string fields of entity. Main entity in my app is Applicant

EDMX Applicant is following

     public partial class Applicant
    {

      public Applicant()
       {
         this.ApplicantEducations = new HashSet<ApplicantEducation>();
         this.ApplicantSkills = new HashSet<ApplicantSkill>();
         this.Applications = new HashSet<Application>();
         this.Experiences = new HashSet<Experience>();
        }

    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<System.DateTime> DOB { get; set; }

   virtual ICollection<ApplicantEducation> ApplicantEducations { get; set; }
   virtual ICollection<ApplicantSkill> ApplicantSkills { get; set; }
   virtual ICollection<Application> Applications { get; set; }
   virtual ICollection<Experience> Experiences { get; set; }
}

I want to search i.e. with Name of institution which is filed in ApplicantEducations of type Institute. Applicant can have one or many ApplicantEducations objects.

Following is my ApplicantEducations's EDMX class

   public partial class ApplicantEducation
{
    public int id { get; set; }
    public Nullable<int> ApplicantId { get; set; }
    public Nullable<int> InstituteId { get; set; }
    public Nullable<int> EducationLevelId { get; set; }
    public Nullable<bool> IsComplete { get; set; }
    public Nullable<System.DateTime> DateStart { get; set; }
    public Nullable<System.DateTime> DateEnd { get; set; }
    public Nullable<short> GPA { get; set; }

    public virtual EducationLevel EducationLevel { get; set; }
    public virtual Institute Institute { get; set; }
    public virtual Applicant Applicant { get; set; }
}

And my Institute entity class is like this

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

  }

So User will search by specifying Name of institute and all applicant will get retrieved with education from that institute.

As I mentioned above the link. Following for example is demonstrated for string field predicate building

     private static Expression<Func<TDbType, bool>> ApplyStringCriterion<TDbType,
        TSearchCriteria>(TSearchCriteria searchCriteria, PropertyInfo searchCriterionPropertyInfo,
        Type dbType, MemberInfo dbFieldMemberInfo, Expression<Func<TDbType, bool>> 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.
        // e.g. 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<TDbType, bool>>;
        // Apply!
        return predicate.And(lambda);
    }

the above code for building a predicate for simple string field contained in main Entity class (Applicant). But Applicant also has ApplicantEducation collection, so my question is how can I create a dynamic query (predicate) for where clause (method) of linq so when user search for institute name then all applicant will get retrieved with same education.

My search criteria is given below,

  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<Models.ApplicantEducationVM> ApplicantEducations { get; set; }
    public ICollection<Models.ExperienceVM> Experiences { get; set; }
    public ICollection<Models.ApplicantSkillsVM> ApplicantSkills { get; set; }

    public ICollection<Models.ApplicationsVM> Applications { get; set; }



}

I am kind of lost how can this be possible.

Thanks

解决方案

You can use the following approach in order to create a Dynamic Where clause in Lambda expression:

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
}

Similarly, the following approach can be applied in order to retrieve only the records starts with the "query" parameter value and retrieving all records if "query" parameter value is null:

IQueryable<StudentViewModel> 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));
}

Or another way with "poor performance":

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

Hope this helps...

这篇关于动态查询,用于使用内部Collection创建谓词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆