繁体   English   中英

如何在C#/ ASP.NET MVC中实现搜索功能

[英]How to implement search functionality in C#/ASP.NET MVC

我正在使用C#和Razor开发ASP.NET MVC 3应用程序。

我有一个看起来像这样的搜索表单: searchform

搜索表单以下列方式工作:

  1. 用户选择他们想要搜索的属性。
  2. 用户选择他们想要匹配搜索字符串的方式(例如包含,开头,结尾,等等)。
  3. 用户输入搜索词并单击“搜索”。

第一个下拉列表中的选择直接与我的ADO.NET Entity Framework模型类中的属性相关(因此直接与表列相关)。

用户需要能够在搜索时明确选择哪个属性和哪个匹配方法,例如用户将明确搜索等于'132'的进程号的所有匹配。

我的第一种方法是使用动态linq从搜索条件构造Where子句( 参见我原来的问题 )。 但是我开始认为这不是最好的方法。

我也希望有一个解决方案,不需要我为每个属性+匹配标准组合硬编码结果。

有关如何实施此搜索的任何建议? 它不必使用我当前的搜索表单,完全接受符合要求的任何其他想法。

您是否考虑过将Lucene.NET用于此项目? 考虑到搜索的性质,使用Lucene进行构建非常简单,因为它允许您根据需要组合不同列上的过滤器

您可以使用代码为谓词构建表达式树。 例如,

public static IQueryable<T> DynamicWhere<T>(this IQueryable<T> src, string propertyName, string value)
{
    var pe = Expression.Parameter(typeof(T), "t");
    var left = Expression.Property(pe, typeof(T).GetProperty(propertyName));
    var right = Expression.Constant(value);
    // Illustrated a equality condition but you can put a switch based on some parameter
    // to have different operators
    var condition = Expression.Equal(left, right);

    var predicate = Expression.Lambda<Func<T, bool>>(condition, pe);
    return src.Where(predicate);
}

将它用作Orders.DynamicWhere(searchBy, searchValue) 您可以添加一个参数来接受运算符,如Equals,Greater Than等,以完成该功能。

有关详细信息,请参阅以下链接

http://msdn.microsoft.com/en-us/library/bb882637.aspx

http://msdn.microsoft.com/en-us/library/bb397951.aspx

还要检查Expression类上的方法列表以获得一个想法。

创建方法并在下面的按钮单击演示中调用它

public List gettaskssdata(int c,int userid,string a,string StartDate,string EndDate,string ProjectID,string statusid){

        List<tbltask> tbtask = new List<tbltask>();


        var selectproject = entity.tbluserprojects.Where(x => x.user_id == userid).Select(x => x.Projectid);

        if (statusid != "" && ProjectID != "" && a != "" && StartDate != "" && EndDate != "")
        {
            int pid = Convert.ToInt32(ProjectID);
            int sid = Convert.ToInt32(statusid);
            DateTime sdate = Convert.ToDateTime(StartDate).Date;
            DateTime edate = Convert.ToDateTime(EndDate).Date;
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblproject.ProjectId == pid) && (x.tblstatu.StatusId == sid) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a)) && (x.StartDate >= sdate && x.EndDate <= edate)).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if (statusid == "" && ProjectID != "" && a != "" && StartDate != "" && EndDate != "")
        {
            int pid = Convert.ToInt32(ProjectID);
            DateTime sdate = Convert.ToDateTime(StartDate).Date;
            DateTime edate = Convert.ToDateTime(EndDate).Date;
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblproject.ProjectId == pid) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a)) && (x.StartDate >= sdate && x.EndDate <= edate)).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if (ProjectID == "" && statusid != "" && a != "" && StartDate != "" && EndDate != "")
        {
            int sid = Convert.ToInt32(statusid);
            DateTime sdate = Convert.ToDateTime(StartDate).Date;
            DateTime edate = Convert.ToDateTime(EndDate).Date;
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblstatu.StatusId == sid) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a)) && (x.StartDate >= sdate && x.EndDate <= edate)).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if(ProjectID!="" && StartDate == "" && EndDate == "" && statusid == ""  && a == "")
        {
            int pid = Convert.ToInt32(ProjectID);
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblproject.ProjectId == pid)).OrderByDescending(x => x.ProjectId).ToList();

        }
        else if(statusid!="" && ProjectID=="" && StartDate == "" && EndDate == ""  && a == "")
        {
            int sid = Convert.ToInt32(statusid);
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblstatu.StatusId == sid) ).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if (a == "" && StartDate != "" && EndDate != "" && ProjectID != "")
        {
            int pid = Convert.ToInt32(ProjectID);
            DateTime sdate = Convert.ToDateTime(StartDate).Date;
            DateTime edate = Convert.ToDateTime(EndDate).Date;
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.ProjectId == pid) && (x.StartDate >= sdate && x.EndDate <= edate)).OrderByDescending(x => x.ProjectId).ToList();

        }
        else if (StartDate == "" && EndDate == "" && statusid != "" && ProjectID != "" && a != "")
        {
            int pid = Convert.ToInt32(ProjectID);
            int sid = Convert.ToInt32(statusid);
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblproject.ProjectId == pid) && (x.tblstatu.StatusId == sid) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a))).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if (a == "" && StartDate == "" && EndDate == "" && ProjectID != "" && statusid != "")
        {
            int pid = Convert.ToInt32(ProjectID);
            int sid = Convert.ToInt32(statusid);
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Include(x => x.tblstatu).Where(x => selectproject.Contains(x.ProjectId) && x.tblproject.company_id == c && x.tblproject.ProjectId == pid && x.tblstatu.StatusId == sid).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if (a != "" && StartDate == "" && EndDate == "" && ProjectID == "" && statusid == "")
        {
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a))).OrderByDescending(x => x.ProjectId).ToList();

        }
        else if (a != "" && ProjectID != "" && StartDate == "" && EndDate == "" && statusid == "")
        {
            int pid = Convert.ToInt32(ProjectID);
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.tblproject.ProjectId == pid) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a))).OrderByDescending(x => x.ProjectId).ToList();
        }
        else if (a != "" && StartDate != "" && EndDate != "" && ProjectID == "" && statusid == "")
        {
            DateTime sdate = Convert.ToDateTime(StartDate).Date;
            DateTime edate = Convert.ToDateTime(EndDate).Date;
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && (x.tblproject.company_id == c) && (x.TaskName.Contains(a) || x.tbUser.User_name.Contains(a)) && (x.StartDate >= sdate && x.EndDate <= edate)).OrderByDescending(x => x.ProjectId).ToList();
        }
        else
        {
            tbtask = entity.tbltasks.Include(x => x.tblproject).Include(x => x.tbUser).Where(x => selectproject.Contains(x.ProjectId) && x.tblproject.company_id == c).OrderByDescending(x => x.ProjectId).ToList();
        }
        return tbtask;

    }

您可以使用Dynamic Linq,您可以使用如下所示的实用程序类创建Where clausole:

public class Criteria 
{
   StringBuilder sb = new StringBuilder();
   bool first = true;

   public void And(string property, string dbOperator, string value) {
       if (first)
       {
           sb.Append(" ").Append(property).Append(" ");
           sb.Append(" ").Append(dbOperator).Append(" ");
           sb.Append(" ").Append(value).Append(" ");
           first = false;
       }
       else
       {
           sb.Append(" && ").Append(property).Append(" ");
           sb.Append(" ").Append(dbOperator).Append(" ");
           sb.Append(" ").Append(value).Append(" ");
       }
   }

   public void Or(string property, string dbOperator, string value)
   {
       if (first)
       {
           sb.Append(" ").Append(property).Append(" ");
           sb.Append(" ").Append(dbOperator).Append(" ");
           sb.Append(" ").Append(value).Append(" ");
           first = false;
       }
       else
       {
           sb.Append(" || ").Append(property).Append(" ");
           sb.Append(" ").Append(dbOperator).Append(" ");
           sb.Append(" ").Append(value).Append(" ");
       }
   }

   public string ToString() 
   {
       return sb.ToString();
   }

}

因此,您可以使用Or或And方法构建具有许多属性的Criteria,并将其放在Dynamic Linq的Where运算符中。

我们开始使用动态linq查询针对我们的Entity Framework模型解析类似的查询。 但是,由于EF被生成的复杂表达式混淆,我们尝试概括查询生成导致性能不佳,因此最终产生了可怕的SQL。

我们使用了Entity SQL

不确定您是否使用MS SQL。 似乎SQL可以为您完成大部分工作,您可以构建动态查询。 显然select / from语句需要工作,但你可以从where子句中获得想法。

DECLARE @SEARCHTYPE VARCHAR(20)
DECLARE @SEARCHTERM VARCHAR(100)

SELECT
    [FIELDS]
FROM
    [TABLE]
WHERE
    (@SEARCHTYPE = 'BEGINSWITH' AND [FIELD] LIKE @SEARCHTERM + '%') OR
    (@SEARCHTYPE = 'ENDSWITH' AND [FIELD] LIKE '%' + @SEARCHTERM) OR
    (@SEARCHTYPE = 'EQUALS' AND [FIELD] = @SEARCHTERM)

您可以将第一个组合数据源设置为myEntityObject.GetType()。GetProperties(),第二个显示可显示的Funcs<string, string, bool> ,如下所示:

public class ComboPredicate
{
    public Func<string, string, bool> Func {get; set;}
    public string Name {get; set; }
}

稍后,当您加载表单时:

comboProperty.Datasource = myEntityObject.GetType().GetProperties()
comboOperation.Datasource = new List<Predicate>
    {
        {
            Name = "Contains",
            Predicate = (s1, s2) => s1 != null && s1.Contains(s2),
        },
        {
            Name = "Equals",
            Predicate = (s1, s2) => string.Compare(s1, s2) == 0,
        },
        //...
    }

之后,当您想要选择实体时:

var propertyInfo = (PropertyInfo)comboProperty.SelectedValue;
var predicate = ((ComboPredicate)comboOperation.SelectedValue).Predicate;
var filteredObjects = objects.Where(o => predicate(propertyInfo.GetValue(o, null).ToString(), textBoxValue.Text));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM