Bueno, el "unir" es complicado, ya que es muy difícil de expresar un join - pero cosas como donde/select/orderby son bastante fáciles ...
Realmente, es solo un caso de combinar los diversos métodos LINQ en IQueryable<T>
, que generalmente aceptan Expression<Func<...>>
para alguna combinación. Por lo que un básico seleccionar 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;
}
yo tendería a volver IQueryable<T>
también, ya que es totalmente componibles. Si la persona que llama desea una lista, siempre pueden usar ToList()
en él ... o (por ejemplo):
using(var ctx = new MyDataContext(CONN))
{
ctx.Log = Console.Out;
int frCount = ctx.Get<Customer>(c => c.Country == "France").Count();
}
cuales (usando Neptuno) hace la consulta:
SELECT COUNT(*) AS [value]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0
El problema con la inclusión el "seleccionar" (proyección) en la consulta es que terminarías 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 del tipo de tabla, y no sería invocable.
En realidad, me pregunto si hay mucho beneficio escribiendo este método en absoluto.Yo podría seguir con un método de base:
public IQueryable<T> Get<T>() where T : class
{
return (IQueryable<T>)GetTable(typeof(T));
}
Y dejar que la persona que llama lo componen en su forma preferida - tal vez con la sintaxis de consulta:
var list = (from cust in ctx.Get<Customer>()
where cust.Country == "France"
select cust.CompanyName).Take(10).ToList();
Qué utiliza:
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 más práctico h; entonces no es necesario especificar el T original (fuente) (que es lo que hace que sea uncallable 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 considerar un método DAL tales como:
public List<string> Countries()
{
return Customers.Get(
x=>x.CompanyName != "",
x=>x.Country,
x=>x).Distinct().ToList();
}
que utiliza (de nuevo, con Neptuno):
SELECT DISTINCT [t0].[Country]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CompanyName] <> @p0
Estoy un poco preocupado por eso, en realidad. El hecho de que compila el predicado significa que siempre cargará toda la tabla y luego hará LINQ-to-Objects sobre él. Eso es ** muy ** ineficiente. –
De acuerdo, tendrá un rendimiento deficiente ... – CMS