visual studio framework ejemplos consulta conexion c# linq linq-to-sql

c# - studio - ¿Cómo hacer una subconsulta en LINQ?



linq to sql vs entity framework (6)

¡Aquí hay una subconsulta para ti!

List<int> IdsToFind = new List<int>() {2, 3, 4}; db.Users .Where(u => SqlMethods.Like(u.LastName, "%fra%")) .Where(u => db.CompanyRolesToUsers .Where(crtu => IdsToFind.Contains(crtu.CompanyRoleId)) .Select(crtu => crtu.UserId) .Contains(u.Id) )

En cuanto a esta parte de la pregunta:

predicateAnd = predicateAnd.And(c => c.LastName.Contains( TextBoxLastName.Text.Trim()));

Recomiendo extraer la cadena del cuadro de texto antes de crear la consulta.

string searchString = TextBoxLastName.Text.Trim(); predicateAnd = predicateAnd.And(c => c.LastName.Contains( searchString));

Desea mantener un buen control sobre lo que se envía a la base de datos. En el código original, una posible lectura es que una cadena no recortada se envía a la base de datos para recortar, lo cual no es un buen trabajo para la base de datos.

Aquí hay un ejemplo de la consulta que intento convertir a LINQ:

SELECT * FROM Users WHERE Users.lastname LIKE ''%fra%'' AND Users.Id IN ( SELECT UserId FROM CompanyRolesToUsers WHERE CompanyRoleId in (2,3,4) )

Existe una relación FK entre CompanyRolesToUsers y los Users , pero es una relación de muchos a muchos y CompanyRolesToUsers es la mesa de conexiones.

Ya tenemos la mayor parte de nuestro sitio creado, y ya tenemos la mayor parte del filtrado trabajando creando expresiones usando una clase PredicateExtensions.

El código para los filtros directos se ve más o menos así:

if (!string.IsNullOrEmpty(TextBoxLastName.Text)) { predicateAnd = predicateAnd.And(c => c.LastName.Contains( TextBoxLastName.Text.Trim())); } e.Result = context.Users.Where(predicateAnd);

Estoy tratando de agregar un predicado para una subselección en otra tabla. ( CompanyRolesToUsers )

Lo que me gustaría poder agregar es algo que hace esto:

int[] selectedRoles = GetSelectedRoles(); if( selectedRoles.Length > 0 ) { //somehow only select the userid from here ???: var subquery = from u in CompanyRolesToUsers where u.RoleID in selectedRoles select u.UserId; //somehow transform this into an Expression ???: var subExpression = Expression.Invoke(subquery); //and add it on to the existing expressions ???: predicateAnd = predicateAnd.And(subExpression); }

¿Hay alguna manera de hacer esto? Es frustrante porque puedo escribir el procedimiento almacenado fácilmente, pero soy nuevo en esta cosa de LINQ y tengo una fecha límite. No he podido encontrar un ejemplo que coincida, pero estoy seguro de que está ahí en alguna parte.


Aquí hay una versión del SQL que devuelve los registros correctos:

select distinct u.* from Users u, CompanyRolesToUsers c where u.Id = c.UserId --join just specified here, perfectly fine and u.firstname like ''%amy%'' and c.CompanyRoleId in (2,3,4)

Además, tenga en cuenta que (2,3,4) es una lista seleccionada de una lista de casilla de verificación por el usuario de la aplicación web, y olvidé mencionar que acabo de codificar eso por simplicidad. Realmente es una matriz de valores CompanyRoleId, por lo que podría ser (1) o (2,5) o (1,2,3,4,6,7,99).

Además, la otra cosa que debería especificar más claramente es que PredicateExtensions se usa para agregar dinámicamente cláusulas predicativas a Where para la consulta, dependiendo de qué campos de formulario haya rellenado el usuario de la aplicación web. Así que la parte más difícil para mí es cómo para transformar la consulta de trabajo en una expresión LINQ que puedo adjuntar a la lista dinámica de expresiones.

Daré algunas de las consultas de muestra de LINQ y veré si puedo integrarlas con nuestro código, y luego publicar mis resultados. ¡Gracias!

marcel


Así es como he estado haciendo subconsultas en LINQ, creo que esto debería conseguir lo que quieres. Puede reemplazar el CompanyRoleId explícito == 2 ... con otra subconsulta para los diferentes roles que desee o unirse también.

from u in Users join c in ( from crt in CompanyRolesToUsers where CompanyRoleId == 2 || CompanyRoleId == 3 || CompanyRoleId == 4) on u.UserId equals c.UserId where u.lastname.Contains("fra") select u;


Bien, aquí hay una consulta de combinación básica que obtiene los registros correctos:

int[] selectedRolesArr = GetSelectedRoles(); if( selectedRolesArr != null && selectedRolesArr.Length > 0 ) { //this join version requires the use of distinct to prevent muliple records //being returned for users with more than one company role. IQueryable retVal = (from u in context.Users join c in context.CompanyRolesToUsers on u.Id equals c.UserId where u.LastName.Contains( "fra" ) && selectedRolesArr.Contains( c.CompanyRoleId ) select u).Distinct(); }

Pero aquí está el código que se integra más fácilmente con el algoritmo que ya teníamos en su lugar:

int[] selectedRolesArr = GetSelectedRoles(); if ( useAnd ) { predicateAnd = predicateAnd.And( u => (from c in context.CompanyRolesToUsers where selectedRolesArr.Contains(c.CompanyRoleId) select c.UserId).Contains(u.Id)); } else { predicateOr = predicateOr.Or( u => (from c in context.CompanyRolesToUsers where selectedRolesArr.Contains(c.CompanyRoleId) select c.UserId).Contains(u.Id) ); }

que es gracias a un póster en el foro LINQtoSQL


No se necesita subconsulta con esta declaración, que está mejor escrita como

select u.* from Users u, CompanyRolesToUsers c where u.Id = c.UserId --join just specified here, perfectly fine and u.lastname like ''%fra%'' and c.CompanyRoleId in (2,3,4)

o

select u.* from Users u inner join CompanyRolesToUsers c on u.Id = c.UserId --explicit "join" statement, no diff from above, just preference where u.lastname like ''%fra%'' and c.CompanyRoleId in (2,3,4)

Dicho esto, en LINQ sería

from u in Users from c in CompanyRolesToUsers where u.Id == c.UserId && u.LastName.Contains("fra") && selectedRoles.Contains(c.CompanyRoleId) select u

o

from u in Users join c in CompanyRolesToUsers on u.Id equals c.UserId where u.LastName.Contains("fra") && selectedRoles.Contains(c.CompanyRoleId) select u

Que de nuevo, son formas respetables de representar esto. Prefiero la sintaxis explícita de "unión" en ambos casos, pero ahí está ...


Podrías hacer algo como esto para tu caso - (la sintaxis puede estar un poco desconectada). También mira este link

subQuery = (from crtu in CompanyRolesToUsers where crtu.RoleId==2 || crtu.RoleId==3 select crtu.UserId).ToArrayList(); finalQuery = from u in Users where u.LastName.Contains(''fra'') && subQuery.Contains(u.Id) select u;