Principales respuestas
Filtros condicionales usando Linq

Pregunta
-
Hola
Trabajo en una app Windows Forms, SQL Server 2014 Express Edition, EF enfoque code first
Tengo un filtro condicional que permite valores null, el detalle es que cuando no le mando parámetros quiero decir que todos los parámetros que mando son null me trae registros de la db. Lo normal sería si no estoy mandando parámetros para que haga una búsqueda no debe traer nada.
Mi consulta linq es la siguiente
using (var context = new BusinessContext()) { var result = from oi in context.OrdenInventarios where (filter.NumeroOrden == null || oi.NumeroOrden.Contains(filter.NumeroOrden)) && (!filter.EstadoOrden.HasValue || oi.EstadoOrden == filter.EstadoOrden) && (filter.FechaEmisionDesde == null || oi.Fecha >= DbFunctions.TruncateTime(filter.FechaEmisionDesde)) && (filter.FechaEmisionHasta == null || oi.Fecha <= DbFunctions.TruncateTime(filter.FechaEmisionHasta)) select new UniversalExtend() { Id = oi.OrdenInventarioId, NumeroComprobante = oi.NumeroOrden, FechaEmision = oi.Fecha, EstadoOrden = oi.EstadoOrden }; return result.ToList(); }
Y haciendo un seguimiento con el SQL Profiler me arroja la siguiente consulta SQL
exec sp_executesql N'SELECT [Extent1].[OrdenInventarioId] AS [OrdenInventarioId], [Extent1].[NumeroOrden] AS [NumeroOrden], [Extent1].[Fecha] AS [Fecha], [Extent1].[EstadoOrden] AS [EstadoOrden] FROM [dbo].[OrdenInventarios] AS [Extent1] WHERE ((@p__linq__0 IS NULL) OR ([Extent1].[NumeroOrden] LIKE @p__linq__1 ESCAPE ''~'')) AND (@p__linq__2 IS NULL OR @p__linq__3 = CAST( [Extent1].[EstadoOrden] AS int)) AND ((@p__linq__4 IS NULL) OR ([Extent1].[Fecha] >= (convert (datetime2, convert(varchar(255), @p__linq__5, 102) , 102)))) AND ((@p__linq__6 IS NULL) OR ([Extent1].[Fecha] <= (convert (datetime2, convert(varchar(255), @p__linq__7, 102) , 102))))', N'@p__linq__0 nvarchar(4000),@p__linq__1 varchar(8000),@p__linq__2 int,@p__linq__3 int, @p__linq__4 datetime2(7),@p__linq__5 datetime2(7), @p__linq__6 datetime2(7),@p__linq__7 datetime2(7)', @p__linq__0=N'', @p__linq__1='%%', @p__linq__2=NULL, @p__linq__3=NULL, @p__linq__4=NULL, @p__linq__5=NULL, @p__linq__6=NULL, @p__linq__7=NULL
Según no me este equivocando en la consulta no hay parámetro alguno, ¿no se porque me trae los registros que hay en la tabla?.
Saludos!
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú
Respuestas
-
>>He comentado cada uno de las condicionales y me sigue trayendo datos
ok, pero eso esta bien, veo todos los parametros en null
ahora si le pasas un valor en alguno, aplica el filtro para ese parametro que asignas
si todo funciona puede que usar un string comparandolo con null no se lleve muy bien, por eso deberias aplicar la tecnica que comente antes de tener una variable bool adicional para resolver cuando es opcional el parametro string
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 16:51
- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:50
-
hola
>>Pero los string no aceptan valores nulos me refiero a esto public string? NumeroOrden ....
el string si permite null, el tema es ver como lo toma linq
Si quitas esta linea
(filter.NumeroOrden == null ||oi.NumeroOrden.Contains(filter.NumeroOrden))
del linq la query funciona y retorna registros ? solo para asegurar que sea ese el parametro del conflicto, pero que el resto funcione de forma condiciona
Quizas para ese filtro debas tener dos parametros uno del tipo bool (HasNumberOrder ) y el otro como string con el valor
filter.NumeroOrden = valor; filter.HasNumberoOrder = !string.IsNullOrEmpty(txtNumeroOrden.Text);
Entonces en el linq quedaria(filter.HasNumeroOrden || oi.NumeroOrden.Contains(filter.NumeroOrden))
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 16:50
- Votado como útil Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 18:59
- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:50
-
hola
>>Estoy usando DbFunctions.TruncateTime pero no me esta trayendo la información que necesito.
vayamos por parte porque se mezcla todo
estabamos con el NumeroOrden, eso se resolvio? trata de quemar etapas para resolver problemas todo junto es imposible entender de donde salen las cosas que cambias
Veo que ya no defines una vlaidacion null en el NumeroOrden, eso porque fue? ya no es un parametro opcional
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Editado Leandro TuttiniMVP viernes, 7 de febrero de 2020 19:40
- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:50
-
>>el detalle es que si mando todos los parámetros null me trae toda la tabla.
Pero si pones un valor en NumeroOrden, puedes validar que cambia el HasNumeroOrden y permite filtrar por ese numero de orden ?
quita del linq todo los demas parametros primero asegurate que uno funciona
despues peude ir agregando el resto, si quieres resolver todo de una no vas a poder, aplica el divide y venceras
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:49
Todas las respuestas
-
Hola Pedro Ávila
Gracias por levantar tu consulta en los foros de MSDN. Con respecto a la misma, te comparto a continuación el siguiente enlace en el cual encontraras un caso similar al que nos estás reportando que te puede servir para entender mejor la estructura de los condicionales
Por favor déjame saber si puedo ofrecerte una mejor respuesta
Gracias por usar los foros de MSDN.
Diana
____
Por favor recuerde "Marcar como respuesta" las respuestas que hayan resuelto su problema, es una forma común de reconocer a aquellos que han ayudado, y hace que sea más fácil para los otros visitantes encontrar la solución más tarde.
Microsoft ofrece este servicio de forma gratuita, con la finalidad de ayudar a los usuarios y la ampliación de la base de datos de conocimientos relacionados con los productos y tecnologías de Microsoft.
Este contenido es proporcionado "tal cual" y no implica ninguna responsabilidad de parte de Microsoft.
- Propuesto como respuesta Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
-
hola
>>no me este equivocando en la consulta no hay parámetro alguno,
veo dos parametro que si estan aplicando
@p__linq__0=N'', @p__linq__1='%%',
esos no estan en NULL
segun entiendo se relaciona con el NumeroOrden
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Propuesto como respuesta Diana AcuñaModerator jueves, 6 de febrero de 2020 22:26
- Votado como útil Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 18:59
-
Hola @Leandro
Tengo un string que es NumeroOrden el cual si esta vació le mando un null
var filter = new CriteriaOrdenInventario() { NumeroOrden = !string.IsNullOrEmpty(txtNumeroOrden.Text) ? txtNumeroOrden.Text : null, EstadoOrden = (int)(cboEstadoOrden.SelectedValue) == -1 ? (EstadoOrden?)null : (EstadoOrden)cboEstadoOrden.SelectedValue, FechaEmisionDesde = chkFechaEmisionDesde.Checked ? (DateTime?)dtpFechaEmisionDesde.Value : null, FechaEmisionHasta = chkFechaEmisionHasta.Checked ? (DateTime?)dtpFechaEmisionHasta.Value : null };
NumeroOrden = txtNumeroOrden lo cambie por la siguiente linea
NumeroOrden = !string.IsNullOrEmpty(txtNumeroOrden.Text) ? txtNumeroOrden.Text : null,
Pero los string no aceptan valores nulos me refiero a esto public string? NumeroOrden ....
Query SQL
exec sp_executesql N'SELECT [Extent1].[OrdenInventarioId] AS [OrdenInventarioId], [Extent1].[NumeroOrden] AS [NumeroOrden], [Extent1].[Fecha] AS [Fecha], [Extent1].[EstadoOrden] AS [EstadoOrden] FROM [dbo].[OrdenInventarios] AS [Extent1] WHERE ((@p__linq__0 IS NULL) OR ([Extent1].[NumeroOrden] LIKE @p__linq__1 ESCAPE ''~'')) AND (@p__linq__2 IS NULL OR @p__linq__3 = CAST( [Extent1].[EstadoOrden] AS int)) AND ((@p__linq__4 IS NULL) OR ([Extent1].[Fecha] >= (convert (datetime2, convert(varchar(255), @p__linq__5, 102) , 102)))) AND ((@p__linq__6 IS NULL) OR ([Extent1].[Fecha] <= (convert (datetime2, convert(varchar(255), @p__linq__7, 102) , 102))))', N'@p__linq__0 nvarchar(4000), @p__linq__1 varchar(8000), @p__linq__2 int, @p__linq__3 int, @p__linq__4 datetime2(7), @p__linq__5 datetime2(7), @p__linq__6 datetime2(7), @p__linq__7 datetime2(7)', @p__linq__0=NULL, @p__linq__1=NULL, @p__linq__2=NULL, @p__linq__3=NULL, @p__linq__4=NULL, @p__linq__5=NULL, @p__linq__6=NULL, @p__linq__7=NULL
El problema es que si no le mando parámetros lo normal no debe traer nada pero esta trayendo registros, es lo que quiero solucionar.
Saludos!
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú- Propuesto como respuesta Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
- Votado como útil Pedro Ávila viernes, 7 de febrero de 2020 17:26
-
hola
>>Pero los string no aceptan valores nulos me refiero a esto public string? NumeroOrden ....
el string si permite null, el tema es ver como lo toma linq
Si quitas esta linea
(filter.NumeroOrden == null ||oi.NumeroOrden.Contains(filter.NumeroOrden))
del linq la query funciona y retorna registros ? solo para asegurar que sea ese el parametro del conflicto, pero que el resto funcione de forma condiciona
Quizas para ese filtro debas tener dos parametros uno del tipo bool (HasNumberOrder ) y el otro como string con el valor
filter.NumeroOrden = valor; filter.HasNumberoOrder = !string.IsNullOrEmpty(txtNumeroOrden.Text);
Entonces en el linq quedaria(filter.HasNumeroOrden || oi.NumeroOrden.Contains(filter.NumeroOrden))
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 16:50
- Votado como útil Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 18:59
- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:50
-
Hola
He quitado NumeroOrden de la consulta linq y me sigue trayendo datos
exec sp_executesql N'SELECT [Extent1].[OrdenInventarioId] AS [OrdenInventarioId], [Extent1].[NumeroOrden] AS [NumeroOrden], [Extent1].[Fecha] AS [Fecha], [Extent1].[EstadoOrden] AS [EstadoOrden] FROM [dbo].[OrdenInventarios] AS [Extent1] WHERE (@p__linq__0 IS NULL OR @p__linq__1 = CAST( [Extent1].[EstadoOrden] AS int)) AND ((@p__linq__2 IS NULL) OR ([Extent1].[Fecha] >= (convert (datetime2, convert(varchar(255), @p__linq__3, 102) , 102)))) AND ((@p__linq__4 IS NULL) OR ([Extent1].[Fecha] <= (convert (datetime2, convert(varchar(255), @p__linq__5, 102) , 102))))', N'@p__linq__0 int, @p__linq__1 int, @p__linq__2 datetime2(7), @p__linq__3 datetime2(7), @p__linq__4 datetime2(7), @p__linq__5 datetime2(7)', @p__linq__0=NULL, @p__linq__1=NULL, @p__linq__2=NULL, @p__linq__3=NULL, @p__linq__4=NULL, @p__linq__5=NULL
He comentado cada uno de las condicionales y me sigue trayendo datos
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú- Editado Pedro Ávila jueves, 6 de febrero de 2020 23:44
- Propuesto como respuesta Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
- Votado como útil Pedro Ávila viernes, 7 de febrero de 2020 17:27
-
>>He comentado cada uno de las condicionales y me sigue trayendo datos
ok, pero eso esta bien, veo todos los parametros en null
ahora si le pasas un valor en alguno, aplica el filtro para ese parametro que asignas
si todo funciona puede que usar un string comparandolo con null no se lleve muy bien, por eso deberias aplicar la tecnica que comente antes de tener una variable bool adicional para resolver cuando es opcional el parametro string
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Propuesto como respuesta Diana AcuñaModerator viernes, 7 de febrero de 2020 16:51
- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:50
-
Hola
En la fecha tengo problemas
ahora si le pasas un valor en alguno, aplica el filtro para ese parametro que asignas
Estoy usando DbFunctions.TruncateTime pero no me esta trayendo la información que necesito.
Mi implementación es la siguiente:
var filter = new CriteriaOrdenInventario() { //NumeroOrden = !string.IsNullOrEmpty(txtNumeroOrden.Text) ? txtNumeroOrden.Text : null, NumeroOrden = txtNumeroOrden.Text, HasNumberOrder = !string.IsNullOrEmpty(txtNumeroOrden.Text), EstadoOrden = (int)(cboEstadoOrden.SelectedValue) == -1 ? (EstadoOrden?)null : (EstadoOrden)cboEstadoOrden.SelectedValue, FechaEmisionDesde = chkFechaEmisionDesde.Checked ? (DateTime?)dtpFechaEmisionDesde.Value.Date : null, FechaEmisionHasta = chkFechaEmisionHasta.Checked ? (DateTime?)dtpFechaEmisionHasta.Value.Date : null };
Query linq
var result = from oi in context.OrdenInventarios where //(filter.NumeroOrden == null || oi.NumeroOrden.Contains(filter.NumeroOrden)) (filter.HasNumberOrder || oi.NumeroOrden.Contains(filter.NumeroOrden)) && (!filter.EstadoOrden.HasValue || oi.EstadoOrden == filter.EstadoOrden.Value) && (filter.FechaEmisionDesde == null || oi.Fecha >= DbFunctions.TruncateTime(filter.FechaEmisionDesde)) && (filter.FechaEmisionHasta == null || oi.Fecha <= DbFunctions.TruncateTime(filter.FechaEmisionHasta)) select new UniversalExtend() { Id = oi.OrdenInventarioId, NumeroComprobante = oi.NumeroOrden, FechaEmision = oi.Fecha, EstadoOrden = oi.EstadoOrden }; return result.ToList();
Nota: Estoy usando EF 6.2.0 ya que estoy usando la versión de .Net Framework 4.7.2, estoy usando el namespace using System.Data.Entity;
En la base de datos tengo la siguiente fecha 2020-02-04 18:04:39 para poder obtener esta fecha en el filtro tengo que ingresar desde 04/02/2020 hasta 05/02/2020, ¿es correcto?, ¿no debería poner en los filtros desde 04/02/2020 hasta 04/02/2020?
¿Por qué salen cuatro fechas?
exec sp_executesql N'SELECT [Extent1].[OrdenInventarioId] AS [OrdenInventarioId], [Extent1].[NumeroOrden] AS [NumeroOrden], [Extent1].[Fecha] AS [Fecha], [Extent1].[EstadoOrden] AS [EstadoOrden] FROM [dbo].[OrdenInventarios] AS [Extent1] WHERE ((@p__linq__0 = 1) OR ([Extent1].[NumeroOrden] LIKE @p__linq__1 ESCAPE ''~'')) AND ((@p__linq__2 IS NULL) OR ([Extent1].[EstadoOrden] = @p__linq__3)) AND ((@p__linq__4 IS NULL) OR ([Extent1].[Fecha] >= (convert (datetime2, convert(varchar(255), @p__linq__5, 102) , 102)))) AND ((@p__linq__6 IS NULL) OR ([Extent1].[Fecha] <= (convert (datetime2, convert(varchar(255), @p__linq__7, 102) , 102))))', N'@p__linq__0 bit, @p__linq__1 varchar(8000), @p__linq__2 int,@p__linq__3 int, @p__linq__4 datetime2(7), @p__linq__5 datetime2(7), @p__linq__6 datetime2(7), @p__linq__7 datetime2(7)', @p__linq__0=0,@p__linq__1='%%', @p__linq__2=NULL, @p__linq__3=NULL, @p__linq__4='2020-02-04 00:00:00', @p__linq__5='2020-02-04 00:00:00', @p__linq__6='2020-02-04 00:00:00', @p__linq__7='2020-02-04 00:00:00'
Saludos!
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú
- Propuesto como respuesta Pablo RubioModerator viernes, 7 de febrero de 2020 17:25
- Votado como útil Pedro Ávila viernes, 7 de febrero de 2020 17:27
- Editado Pedro Ávila viernes, 7 de febrero de 2020 17:35
-
hola
>>Estoy usando DbFunctions.TruncateTime pero no me esta trayendo la información que necesito.
vayamos por parte porque se mezcla todo
estabamos con el NumeroOrden, eso se resolvio? trata de quemar etapas para resolver problemas todo junto es imposible entender de donde salen las cosas que cambias
Veo que ya no defines una vlaidacion null en el NumeroOrden, eso porque fue? ya no es un parametro opcional
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Editado Leandro TuttiniMVP viernes, 7 de febrero de 2020 19:40
- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:50
-
Hola
Si lo sigue siendo, lo que pasa que lo comente para comprobar las fechas, el detalle es que si mando todos los parámetros null me trae toda la tabla.
Con la solución que me diste ingreso un número de orden y me trae toda la tabla pero con esta:
(filter.NumeroOrden == null || oi.NumeroOrden.Contains(filter.NumeroOrden))
Si me funciona bien.
El detalle es que en todos los casos si le mando null me trae toda la tabla, después cuando le mando los parámetros si me trae lo que le pideo, excepto la fecha que si quiero la fecha 04/02/2020 tengo que poner un filtro de 04/02/2020 hasta 05/02/2020.
Pero sigo sin entender por que si no le mando parámetros me trae toda la tabla.
No se si lo mejor será quitar el TruncateTime y mandarle la fechas de las siguiente manera "desde las cero horas hasta las 23:59:59"
Saludos!
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú
- Editado Pedro Ávila viernes, 7 de febrero de 2020 19:59
-
>>el detalle es que si mando todos los parámetros null me trae toda la tabla.
Pero si pones un valor en NumeroOrden, puedes validar que cambia el HasNumeroOrden y permite filtrar por ese numero de orden ?
quita del linq todo los demas parametros primero asegurate que uno funciona
despues peude ir agregando el resto, si quieres resolver todo de una no vas a poder, aplica el divide y venceras
saludos
Leandro Tuttini
Blog
MVP Profile
Buenos Aires
Argentina- Marcado como respuesta Pedro Ávila viernes, 7 de febrero de 2020 23:49
-
Hola
Usando HasNumeroOrden cuando no envio datos es false y cuando le asigno un dato es true hasta ahí esta bien todo pero cuando trae los datos me trae todos no el numero de orden especifico.
(filter.HasNumberOrder || oi.NumeroOrden.Contains(filter.NumeroOrden))
exec sp_executesql N'SELECT [Extent1].[OrdenInventarioId] AS [OrdenInventarioId], [Extent1].[NumeroOrden] AS [NumeroOrden], [Extent1].[Fecha] AS [Fecha], [Extent1].[EstadoOrden] AS [EstadoOrden] FROM [dbo].[OrdenInventarios] AS [Extent1] WHERE (@p__linq__0 = 1) OR ([Extent1].[NumeroOrden] LIKE @p__linq__1 ESCAPE ''~'')', N'@p__linq__0 bit, @p__linq__1 varchar(8000)', @p__linq__0=1, @p__linq__1='%0000000002%'
Hay un parametro 0 que tiene un valor 1 cuando lo quito si me trae lo que pido modificando desde el sql
Solo se le esta preguntando por un dato especifico y trae toda la tabla.
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú
- Editado Pedro Ávila viernes, 7 de febrero de 2020 21:38
-
Leandro
Tu técnica funciona!
Cambiando el linq de : (filter.NumeroOrden == null || oi.NumeroOrden.Contains(filter.NumeroOrden))
Por
(filter.HasNumberOrder && oi.NumeroOrden.Contains(filter.NumeroOrden))
El resultado es si le mando un parámetro me trae lo que le pido y si no le mando nada no me trae nada como debe ser.
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú -
Leandro
Funciono
Ya logre solucionar NumeroOrden y EstadoOrden la query de linq a cambiado
var filter = new CriteriaOrdenInventario() { NumeroOrden = txtNumeroOrden.Text, HasNumberOrder = !string.IsNullOrEmpty(txtNumeroOrden.Text), EstadoOrden = (EstadoOrden)cboEstadoOrden.SelectedValue, HasEstadoOrden = (int)cboEstadoOrden.SelectedValue != (int)(-1).GetHashCode(), FechaEmisionDesde = chkFechaEmisionDesde.Checked ? (DateTime?)dtpFechaEmisionDesde.Value : null, FechaEmisionHasta = chkFechaEmisionHasta.Checked ? (DateTime?)dtpFechaEmisionHasta.Value: null };
Query Linq
var result = from oi in context.OrdenInventarios where (filter.HasNumberOrder && oi.NumeroOrden.Contains(filter.NumeroOrden)) || (filter.HasEstadoOrden && oi.EstadoOrden == filter.EstadoOrden) //|| //(filter.FechaEmisionDesde == null || oi.Fecha >= DbFunctions.TruncateTime(filter.FechaEmisionDesde)) //&& //(filter.FechaEmisionHasta == null || oi.Fecha < DbFunctions.TruncateTime(filter.FechaEmisionHasta)) select new UniversalExtend() { Id = oi.OrdenInventarioId, NumeroComprobante = oi.NumeroOrden, FechaEmision = oi.Fecha, EstadoOrden = oi.EstadoOrden }; return result.ToList();
Solo me falta solucionar lo de la fecha, eso lo voy a poner en otro hilo esto ya se hizo extenso.
Gracias eres un crack!
Pedro Ávila
"El hombre sabio querrá estar siempre con quien sea mejor que él."
Lima - Perú