Как реализовать функцию поиска в С#/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;
}