Как реализовать функцию поиска в С#/ASP.NET MVC

Я разрабатываю приложение ASP.NET MVC 3 с использованием С# и Razor.

У меня есть форма поиска, которая выглядит так: searchform

Форма поиска работает следующим образом:

  • Пользователь выбирает, какое свойство они хотят искать.
  • Пользователь выбирает, как они должны соответствовать строке поиска (например, содержит, начинается с, заканчивается на, равно, и т.д.).
  • Пользователь вводит поисковый запрос и нажимает Поиск.

Выбор в первом раскрывающемся списке связан непосредственно с свойством в моем классе модели Entity Framework ADO.NET(и, следовательно, непосредственно в столбец таблицы).

Пользователям требуется возможность явно выбирать какое свойство и какой метод сопоставления при поиске, например. пользователь будет явно искать все совпадения номера процесса, равного "132".

Мой первый подход состоял в том, чтобы использовать динамический linq для построения предложения Where из критериев поиска (см. мой исходный вопрос). Однако я начинаю думать, что это не лучший способ сделать это.

Я также надеюсь на решение, которое не требует от меня жесткого кода результата для каждой комбинации свойств + соответствия.

Любые предложения о том, как я должен выполнять этот поиск? Он не должен использовать мою текущую форму поиска, полностью открытую для любых других идей, которые соответствуют требованиям.

Ответ 1

Вы можете построить дерево выражений для того, где предикат использует код. Например,

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, чтобы получить представление.

Ответ 2

Вы изучали использование Lucene.NET для этого проекта? учитывая характер ваших поисков, было бы очень просто построить это с помощью Lucene, так как он позволяет объединять фильтры по разным столбцам так же, как ваши требования.

Ответ 3

Вы можете использовать Dynamic Linq, и вы можете создать клаузулу Where с таким классом утилиты, как это:

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 и поместить их в оператор Where Dynamic Linq.

Ответ 4

Мы начали решение подобных запросов против нашей модели Entity Framework с использованием динамических запросов linq. Тем не менее, наши попытки обобщения генерации запросов приводили к плохой производительности из-за того, что EF путают возникающие сложные выражения, поэтому в итоге был выпущен ужасный SQL.

Мы обратились к Entity SQL.

Ответ 5

Не уверен, что вы используете 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)

Ответ 6

У вас может быть первый источник данных combo для 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));

Ответ 7

создайте метод и назовите его нажатием кнопки мыши ниже

public Список gettaskssdata (int c, int userid, строка a, строка StartDate, строка EndDate, строка ProjectID, строка 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;

    }