2011-08-29 23 views
10

Estoy desarrollando una aplicación ASP.NET MVC 3 usando C# y Razor.Cómo implementar la funcionalidad de búsqueda en C#/ASP.NET MVC

que tienen un formulario de búsqueda que tiene este aspecto: searchform

El formulario de búsqueda funciona de la siguiente manera:

  1. El usuario selecciona el que la propiedad que quieren buscar en.
  2. El usuario selecciona cómo quiere que coincida con la cadena de búsqueda (por ejemplo, contiene, comienza con, termina con, iguales, etc.).
  3. El usuario ingresa un término de búsqueda y hace clic en Buscar.

Las selecciones en el primer menú desplegable se relacionaron directamente con una propiedad en mi clase de modelo de ADO.NET Entity Framework (y, por lo tanto, directamente en una columna de la tabla).

Los usuarios necesitan la capacidad de seleccionar explícitamente qué propiedad y qué método de coincidencia al buscar, p. un usuario buscará explícitamente todas las coincidencias del número de proceso que sea igual a '132'.

Mi primer enfoque fue utilizar dynamic linq para construir una cláusula Where a partir de los criterios de búsqueda (see my original question). Sin embargo, estoy empezando a pensar que esta no es la mejor manera de hacerlo.

También espero una solución que no requiera que codifique el resultado para cada propiedad + combinación de criterios coincidentes.

¿Alguna sugerencia sobre cómo debo implementar esta búsqueda? No tiene que estar utilizando mi formulario de búsqueda actual, totalmente abierto a cualquier otra idea que se ajuste a los requisitos.

+7

ya sabes, esto es tan viejo! En nuestra aplicación tendremos una búsqueda rápida tan simple como Google Chrome o la barra de direcciones de IE 9 donde puede ingresar una url o buscar por texto. Ya no es necesario especificar el nombre o las condiciones de la columna, solo hacer una búsqueda de texto completo en columnas significativas y combinar resultados con otras combinaciones posibles, una experiencia de usuario más sencilla y fluida. Nuestros usuarios adoran esto después de una primera fase de "sentirse perdido": D –

+3

No estoy seguro de si ese tipo de búsqueda proporcionaría la especificidad que necesitan nuestros usuarios. Necesitan poder especificar explícitamente si quieren contener, iguales, etc., y quiero evitar forzarlos a aprender alguna sintaxis de cadena para lograr esto. Siéntase libre de poner su sugerencia como una respuesta. – link664

+0

Si modelas la propiedad, el operador y el término como 3 entidades distintas, no entiendo por qué la opción 'dynamic linq' te obligaría a codificar cualquier cosa. Construiría la consulta de Linq esperada, como una cadena, a partir de la información recopilada de las 3 entidades. Por ejemplo, puede crear una propiedad LinkOperation a la entidad Operator que lo ayudará a construir esta cadena. –

Respuesta

3

Puede construir el árbol de expresiones para donde el predicado usa el código. Por ejemplo,

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

Úselo como Orders.DynamicWhere(searchBy, searchValue). Puede agregar un parámetro más para aceptar el operador como Equals, Greater Than, etc. para completar la función.

Consulte estos enlaces para más información:

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

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

también comprobar list of methods on the Expression class para tener una idea.

+0

Parece un gran enfoque. Gracias. Desafortunadamente, en mi caso necesito comparar una propiedad en una tabla relacionada a 'T'. (La otra tabla tiene un FK en mi tabla 'T' pero solo estoy interesado en una fila si accidentalmente hay más.) Después de pasar mucho tiempo con esto, no veo cómo puedo modificar esto para respaldar una propiedad en una tabla relacionada. –

12

¿Has buscado utilizar Lucene.NET para este proyecto? dada la naturaleza de sus búsquedas, sería muy sencillo construir eso usando Lucene, ya que le permite combinar filtros en diferentes columnas como sus requisitos

+0

¿Lucene no es una biblioteca de búsqueda/indexación de documentos? Mis búsquedas no son búsquedas en páginas/contenido en páginas, son búsquedas en un modelo de Entity Framework. – link664

+0

Lucene es bueno para la indexación de texto completo. Pero SQL Server también tiene un servicio de indexación de texto completo. También debo señalar que una búsqueda de texto completo es solo un tipo de búsqueda. –

+0

Exactamente. Y no estoy seguro de cómo me ayudaría la indexación de texto completo en este caso cuando no estoy haciendo una especie de búsqueda general "búscame todo en mi base de datos que contenga este valor". – link664

0

Puede usar Dynamic Linq y puede crear el Where clausole con una utilidad clase como esta:

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(); 
    } 

} 

para que pueda construir un Criterios con muchas propiedades utilizando métodos o o y y ponerlo en el caso del operador dinámico LINQ.

0

Comenzamos resolviendo consultas similares contra nuestro modelo de Entity Framework utilizando consultas dinámicas de linq.Sin embargo, nuestros intentos de generalizar la generación de consultas dieron como resultado un mal rendimiento debido a que EF se confunde con las expresiones complejas resultantes, por lo que al final se produjo SQL horrible.

Recurrimos a Entity SQL.

0

No estoy seguro si está usando MS SQL. Parece que SQL podría hacer la mayor parte del trabajo por usted, y puede crear consultas dinámicas. Obviamente, la instrucción select/from necesita funcionar, pero puede obtener la idea de la cláusula 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) 
0

Usted podría tener la primera fuente de datos combinado establecido en myEntityObject.GetType() (GetProperties), el segundo a una lista de visualizable Funcs<string, string, bool>, como esto:.

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

Más tarde, cuando se cargar el formulario:

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, 
     }, 
     //... 
    } 

Y más tarde, cuando se quiere elegir sus entidades:

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

crear método y llamar a él en el botón clic demostración a continuación

Lista pública gettaskssdata (int c, int id de usuario, String, cadena StartDate, EndDate cadena, Proyectólo secuencia, secuencia de 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; 

    } 
Cuestiones relacionadas