c# linq linq-to-sql .net-3.5

c# - Consultas condicionales de Linq



linq-to-sql .net-3.5 (11)

Estamos trabajando en un Visor de registro. El uso tendrá la opción de filtrar por usuario, gravedad, etc. En los días Sql, agregaría a la cadena de consulta, pero quiero hacerlo con Linq. ¿Cómo puedo agregar condicionalmente cláusulas where?


Bueno, lo que pensé era que podrías poner las condiciones del filtro en una lista genérica de Predicados:

var list = new List<string> { "me", "you", "meyou", "mow" }; var predicates = new List<Predicate<string>>(); predicates.Add(i => i.Contains("me")); predicates.Add(i => i.EndsWith("w")); var results = new List<string>(); foreach (var p in predicates) results.AddRange(from i in list where p.Invoke(i) select i);

Eso da como resultado una lista que contiene "me", "meyou" y "mow".

Podrías optimizar eso haciendo foreach con los predicados en una función totalmente diferente que ORs todos los predicados.


Cuando se trata de linq condicional, soy muy aficionado al patrón de filtros y tuberías.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

Básicamente, usted crea un método de extensión para cada caso de filtro que toma IQueryable y un parámetro.

public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; }


Haciendo esto:

bool lastNameSearch = true/false; // depending if they want to search by last name,

teniendo esto en la declaración where :

where (lastNameSearch && name.LastNameSearch == "smith")

significa que cuando se crea la consulta final, si lastNameSearch es false la consulta omitirá por completo cualquier SQL para la búsqueda del apellido.


No es lo más bonito, pero puedes usar una expresión lambda y aprobar tus condiciones de manera opcional. En TSQL hago mucho de lo siguiente para que los parámetros sean opcionales:

WHERE Field = @FieldVar O @FieldVar IS NULL

Podría duplicar el mismo estilo con la siguiente lambda (un ejemplo de comprobación de autenticación):

MyDataContext db = new MyDataContext ();

void RunQuery (string param1, string param2, int? param3) {

Func checkUser = usuario =>

((param1.Length> 0)? user.Param1 == param1: 1 == 1) &&

((param2.Length> 0)? user.Param2 == param2: 1 == 1) &&

((param3! = null)? user.Param3 == param3: 1 == 1);

Usuario foundUser = db.Users.SingleOrDefault (checkUser);

}


Otra opción sería usar algo como el PredicateBuilder discutido here . Le permite escribir código como el siguiente:

var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone"); var classics = Product.ContainsInDescription ("Nokia", "Ericsson") .And (Product.IsSelling()); var query = from p in Data.Products.Where (newKids.Or (classics)) select p;

Tenga en cuenta que solo tengo esto para trabajar con Linq 2 SQL. EntityFramework no implementa Expression.Invoke, que se requiere para que este método funcione. Tengo una pregunta con respecto a este problema here .


Puedes usar un método externo:

var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... }

Esto funcionaría, pero no se puede dividir en árboles de expresiones, lo que significa que Linq to SQL ejecutaría el código de verificación contra cada registro.

Alternativamente:

var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec;

Eso podría funcionar en árboles de expresiones, lo que significa que Linq to SQL estaría optimizado.


Recientemente tuve un requerimiento similar y eventualmente encontré esto en MSDN. Muestras de CSharp para Visual Studio 2008

Las clases incluidas en el ejemplo de DynamicQuery de la descarga le permiten crear consultas dinámicas en tiempo de ejecución en el siguiente formato:

var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)");

Al usar esto, puede construir una cadena de consulta dinámicamente en tiempo de ejecución y pasarla al método Where ():

string dynamicQueryString = "City = /"London/" and Order.Count >= 10"; var q = from c in db.Customers.Where(queryString, null) orderby c.CompanyName select c;


Si necesita filtrar base en una lista / matriz, use lo siguiente:

public List<Data> GetData(List<string> Numbers, List<string> Letters) { if (Numbers == null) Numbers = new List<string>(); if (Letters == null) Letters = new List<string>(); var q = from d in database.table where (Numbers.Count == 0 || Numbers.Contains(d.Number)) where (Letters.Count == 0 || Letters.Contains(d.Letter)) select new Data { Number = d.Number, Letter = d.Letter, }; return q.ToList(); }


Solo use el operador C # &&:

var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")

Editar: Ah, necesito leer más cuidadosamente. Querías saber cómo agregar cláusulas adicionales condicionalmente . En ese caso, no tengo idea. :) Lo que probablemente haría es solo preparar varias consultas y ejecutar la correcta, dependiendo de lo que terminé necesitando.


Terminé usando una respuesta similar a la de Daren, pero con una interfaz IQueryable:

IQueryable<Log> matches = m_Locator.Logs; // Users filter if (usersFilter) matches = matches.Where(l => l.UserName == comboBoxUsers.Text); // Severity filter if (severityFilter) matches = matches.Where(l => l.Severity == comboBoxSeverity.Text); Logs = (from log in matches orderby log.EventTime descending select log).ToList();

Eso construye la consulta antes de llegar a la base de datos. El comando no se ejecutará hasta que aparezca .ToList () al final.


si solo quiere filtrar si se pasan ciertos criterios, haga algo como esto

var logs = from log in context.Logs select log; if (filterBySeverity) logs = logs.Where(p => p.Severity == severity); if (filterByUser) logs = logs.Where(p => p.User == user);

Si lo hace de esta manera, permitirá que su árbol de expresiones sea exactamente lo que desea. De esta forma, el SQL creado será exactamente lo que necesita y nada menos.