我遇到了一些dbml生成的类,这些类无法解析为高效的SQL。想象一下,我有一个Accounts表和一个Transactions表,其中每个事务都与一个特定的帐户相关联。我将所有这些加载到dbml中,并弹出一个Account类和一个Transaction类。 Account类具有对一组事务的EntitySet引用,这些事务表示该帐户上的所有事务。很公平。
现在假设我只想要当前会计期间的交易。所以我添加一个这样的方法:
public IEnumerable<Transaction> CurrentTransactions
{
get
{
DateTime dtStart = CurrentPeriod;
DateTime dtEnd = NextPeriod;
return
from t in Transactions
orderby t.date
where t.date >= CurrentPeriod && t.date <= NextPeriod
select t;
}
}
看起来很好并且有效,但SQL不好:
SELECT [t0].[id], [t0].[account_id], [t0].[date], [t0].[description], [t0].[amount], [t0].[sign]
FROM [dbo].[transactions] AS [t0]
WHERE [t0].[account_id] = @p0
即:它将整个事务集拉下来并使用LINQ for Objects处理它。我已经尝试取出where子句,orderby子句,用常量替换日期,它仍然是客户端完成的。
为了比较,我尝试直接在数据上下文中调用Transactions集合:
DateTime dtStart = account.CurrentPeriod;
DateTime dtEnd = account.NextPeriod;
IEnumerable<Transaction> trans=
from t in MyDataContext.Transactions
orderby t.date
where t.date >= dtStart && t.date <= dtEnd && t.account_id==iAccountID
select t;
并且效果很好:
SELECT [t0].[id], [t0].[account_id], [t0].[date], [t0].[description], [t0].[amount], [t0].[sign]
FROM [dbo].[transactions] AS [t0]
WHERE ([t0].[date] >= @p0) AND ([t0].[date] <= @p1) AND ([t0].[account_id] = @p2)
ORDER BY [t0].[date]
毕竟,我有两个问题:
答案 0 :(得分:6)
遗憾的是,你无法做到这一点。为LINQ to SQL实体类生成的集合属性不是IQueryable
;因此,对它们执行的任何查询都将使用LINQ to Objects。这是设计的。正如您自己注意到的那样,为了获得有效的查询,您必须查询从Transactions
获取的DataContext
,但您的财产gettor中没有。{/ p>
此时您的选项是:
DataContext
为参数的方法;或EntitySet
就可以存储它,虽然是间接的 - 当然这是版本特定的,容易破损等等。据我所知,Entity Framework没有此限制,因为它的集合属性为ObjectQuery<T>
- IQueryable
。
答案 1 :(得分:3)
第一个例子中 Transactions 的类型是什么?
请记住您正在使用扩展方法。使用的Linq扩展方法取决于接口 Transactions implements:
编辑:
这是EntitySet类型的指纹:
public sealed class EntitySet<TEntity> : IList,
ICollection, IList<TEntity>, ICollection<TEntity>, IEnumerable<TEntity>,
IEnumerable, IListSource
where TEntity : class
回答你的问题:
答案 2 :(得分:0)
从使用IEnumerable切换到IQueryable,您的SQL将被优化为仅按需提供所需内容。