sintaxis ordenar lectura expresiones ejemplos datos consultas consulta con clausula buscar c# linq linq-to-sql expression-trees

c# - lectura - ordenar en linq



En LINQ to SQL, ¿cómo se pasan partes de una consulta LINQ a una función? (5)

¿Es posible pasar partes de una consulta de linq a una función? Quiero crear una interfaz común para mi DAL que siempre usa la misma interfaz de consulta. Por ejemplo,

List<T> Get(Join j, Where w, Select s){ return currentDataContext<T>.Join(j).Where(w).Select(s).ToList(); }

¿Es posible este tipo de cosas? Estoy pensando que se haría con árboles de expresiones, pero no he podido encontrar ejemplos de ello.


Bueno, el "join" es complicado, porque es muy difícil expresar un join, pero cosas como where / select / orderby son bastante fáciles ...

En realidad, solo se trata de combinar varios métodos LINQ en IQueryable<T> , que generalmente aceptan Expression<Func<...>> para alguna combinación. Entonces, una selección básica con un predicado opcional sería:

public IQueryable<T> Get<T>( Expression<Func<T,bool>> predicate ) where T : class { IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T)); if (predicate != null) query = query.Where(predicate); return query; }

IQueryable<T> a devolver IQueryable<T> también, ya que es totalmente composable. Si la persona que llama desea una lista, siempre puede usar ToList() en ella ... o (por ejemplo):

using(var ctx = new MyDataContext(CONN)) { ctx.Log = Console.Out; int frCount = ctx.Get<Customer>(c => c.Country == "France").Count(); }

que (usando Northwind) hace la consulta:

SELECT COUNT(*) AS [value] FROM [dbo].[Customers] AS [t0] WHERE [t0].[Country] = @p0

El problema con incluir el "seleccionar" (proyección) en la consulta es que terminaría con múltiples tipos genéricos. Como a menudo quiere que la proyección sea de tipo anónimo, sería bastante imposible especificar el tipo de proyección (anónimo) y el tipo de tabla, y no sería invocable.

En realidad, me pregunto si hay mucho beneficio escribiendo este método en absoluto. Podría seguir con un método base:

public IQueryable<T> Get<T>() where T : class { return (IQueryable<T>)GetTable(typeof(T)); }

Y deje que quien llama lo componga de la forma que prefiera, quizás con la sintaxis de la consulta:

var list = (from cust in ctx.Get<Customer>() where cust.Country == "France" select cust.CompanyName).Take(10).ToList();

Qué usos:

SELECT TOP (10) [t0].[CompanyName] FROM [dbo].[Customers] AS [t0] WHERE [t0].[Country] = @p0

Alternativamente, si realmente desea incluir el orden por y la proyección, entonces un método de extensión es el enfoque más práctico; entonces no necesita especificar el original (fuente) T (que es lo que lo hace incalable cuando se mezcla con anon-types):

public static class QueryExtension { public static IQueryable<TProjection> Get<TSource, TProjection, TOrderKey>( this IQueryable<TSource> source, Expression<Func<TSource, bool>> where, // optional Expression<Func<TSource, TProjection>> select, Expression<Func<TProjection, TOrderKey>> orderBy) { if (where != null) source = source.Where(where); return source.Select(select).OrderBy(orderBy); } }

Luego considere un método DAL como:

public List<string> Countries() { return Customers.Get( x=>x.CompanyName != "", x=>x.Country, x=>x).Distinct().ToList(); }

¿Qué usos (de nuevo, con Northwind):

SELECT DISTINCT [t0].[Country] FROM [dbo].[Customers] AS [t0] WHERE [t0].[CompanyName] <> @p0


Puede usar Dynamic LINQ y pasar los parámetros en forma de cadenas.


Puede usar la biblioteca Dynamic Expression disponible con Linq Examples, con esta biblioteca de extensión puede pasar las cláusulas linq para donde etc ...

Descarga disponible desde aquí linq samples


Verifique esta clase genérica: TableView.cs .

Básicamente utiliza un delegado Func <TEntity, bool> para aplicar el predicado Where:

//... public TableView(DataContext dataContext, Expression<Func<TEntity, bool>> predicate) { this.table = dataContext.GetTable<TEntity>(); this.baseQuery = table.Where(predicate); this.predicate = predicate.Compile(); } //...


Marc Gravell ♦, como siempre, proporcionó una respuesta muy perspicaz, pero realmente creo que tener métodos que tomen IQueryables y agregar restricciones funcionaría en la mayoría de los casos y mantendrían el código más claro y fácil de mantener. Por ejemplo:

//Join public static IQueryable<IContract> AllContracts(this IQueryable<IAccount> accounts, ISession s ) { return from a in accounts from contract in s.Query<IContract() where (a.Id == contract.AccountId) select contract; } //Where public static IQueryable<IContract> Active(this IQueryable<IContract> contracts) { return from contract in contracts where (contract.Active == true) select contract; }

Entonces puedes mezclar y unir estos como estos:

IQueryable<IContract> activeContracts = s.Query<IAccount>() .Where(o => o.Name == "XXX") .GetContracts(s) .Active();

Estoy usando métodos de extensión y el LINQ de NHiberante que proporciona el método Query aquí, pero esto podría reescribirse fácilmente sin métodos estáticos y con ningún proveedor LINQ.