嗯,“加入”很棘手,因为很难表达一个加入 - 但是像 where / select / orderby 这样的事情很容易......
真的,这只是在IQueryable<T> 上组合各种LINQ 方法的情况,它们通常接受Expression<Func<...>> 进行某种组合。因此,带有可选谓词的基本选择将是:
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>,因为它是完全可组合的。如果调用者想要一个列表,他们总是可以在上面使用ToList()...或者(例如):
using(var ctx = new MyDataContext(CONN))
{
ctx.Log = Console.Out;
int frCount = ctx.Get<Customer>(c => c.Country == "France").Count();
}
哪个(使用 Northwind)进行查询:
SELECT COUNT(*) AS [value]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0
在查询中包含“选择”(投影)的问题是您最终会得到多个泛型类型。由于您经常希望投影是匿名类型,因此几乎不可能指定投影类型(匿名)和表类型,并且它是不可调用的。
实际上,我想知道编写这样的方法是否有很多好处。我可能会坚持使用基本方法:
public IQueryable<T> Get<T>() where T : class
{
return (IQueryable<T>)GetTable(typeof(T));
}
并让调用者以他们喜欢的方式编写它——也许使用查询语法:
var list = (from cust in ctx.Get<Customer>()
where cust.Country == "France"
select cust.CompanyName).Take(10).ToList();
用途:
SELECT TOP (10) [t0].[CompanyName]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0
或者,如果您确实想包含 order by 和 projection,那么扩展方法是最实用的方法;那么你不需要指定原始(源) T (这就是它在与匿名类型混合时无法调用的原因):
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);
}
}
然后考虑一个 DAL 方法,例如:
public List<string> Countries()
{
return Customers.Get(
x=>x.CompanyName != "",
x=>x.Country,
x=>x).Distinct().ToList();
}
使用(同样,与 Northwind):
SELECT DISTINCT [t0].[Country]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CompanyName] <> @p0