LINQ到SQL EntitySet中的泄漏抽象
我遇到了一些dbml生成的类的问题,这些类不需要解析为高效的SQL。假设我有一个Accounts表和一个Transactions表,其中每个事务都与一个特定的帐户相关联。我将所有这些加载到dbml中,并弹出一个Account类和一个Transaction类。Account类有一个EntitySet引用,该引用指向表示该帐户上所有事务的事务集合。很公平 现在假设我只想要当前会计期间的交易记录。因此,我添加了如下方法:LINQ到SQL EntitySet中的泄漏抽象,linq,linq-to-sql,entity-framework,Linq,Linq To Sql,Entity Framework,我遇到了一些dbml生成的类的问题,这些类不需要解析为高效的SQL。假设我有一个Accounts表和一个Transactions表,其中每个事务都与一个特定的帐户相关联。我将所有这些加载到dbml中,并弹出一个Account类和一个Transaction类。Account类有一个EntitySet引用,该引用指向表示该帐户上所有事务的事务集合。很公平 现在假设我只想要当前会计期间的交易记录。因此,我添加了如下方法: public IEnumerable<Transaction> Cu
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;
}
}
Ie:它将整个事务集拉下来,并使用LINQ for Object进行处理。我试着去掉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;
DateTime dtStart=account.CurrentPeriod;
DateTime dtEnd=account.NextPeriod;
IEnumerable trans=
来自MyDataContext.Transactions中的t
订购日期
其中,t.date>=dtStart&&t.date=@p0)和([t0].[date]从使用IEnumerable全境切换到IQueryable,您的SQL将被优化为只按需拉取您需要的事务。第一个示例中的事务类型是什么
请记住,您使用的是扩展方法。所使用的Linq扩展方法取决于接口事务实现:
- IQueryable将是linq到sql或linq到实体或
- IEnumerable将为对象提供linq
编辑:
这是EntitySet类型的指纹:
public sealed class EntitySet<TEntity> : IList,
ICollection, IList<TEntity>, ICollection<TEntity>, IEnumerable<TEntity>,
IEnumerable, IListSource
where TEntity : class
公共密封类EntitySet:IList,
ICollection,IList,ICollection,IEnumerable,
IEnumerable,IListSource
地点:班级
回答您的问题:
事务未实现IQueryable,因此这是正确的行为
您的account类需要能够引用Transactions表对象
遗憾的是,您无法做到这一点。为LINQ to SQL实体类生成的集合属性不是IQueryable
;因此,对它们执行的任何查询都将使用LINQ to对象。这是出于设计。正如您自己正确指出的,要获得高效查询,您必须查询从数据中获取的事务aContext
,但属性gettor中没有
此时,您可以选择:
- 使其成为以
DataContext
为参数的方法;或
- 使用reflection hackery检索上下文-实体本身不存储上下文,但其上的EntitySet
s存储上下文,尽管是间接的-这自然是特定于版本的,容易被破坏,等等
据我所知,实体框架没有这个限制,因为它的集合属性是ObjectQuery
,这是IQueryable
,它不会。他的问题是Transactions
不是IQueryable
,他不能对它做任何事情(它是一个EntitySet
,必须是一个).Yep这正是问题所在。Argh.从来不是一个简单的解决方案。:)事务是dbml生成的EntitySet属性。[Association(Name=“Account\u Transaction”,Storage=“\u Transactions”,ThisKey=“id”,OtherKey=“Account\u id”)]公共实体设置事务2)。我理解这一点,问题是,如果帐户对象通常由数据上下文/实体框架创建,那么如何获得这样的引用?我将在何处连接以向account对象传递对transactions表的引用?或者,换句话说,给定一个与特定数据上下文关联的实体对象,如何从该实体返回其数据上下文?您是在扩展Account对象的功能,对吗?是否添加参数化方法调用?IEnumerable GetCurrentTransactions(DataContext ctx)我假设Account对象定义为分部类,或者您可以创建一个扩展方法。Yes Account对象是分部类。我想将dc传递给方法是可以的,只是我使用Account对象作为强类型MVC视图的类型,而我目前没有可用的dc。考虑到这一点,我想我会重新安排它,为MVC视图使用一个新对象,直接从dc而不是通过帐户获取事务。尽管如此,我还是对dbml生成的类如此容易泄漏感到惊讶——我认为我所尝试的是一种相当标准的东西。至少从2009年到现在,Entity Framework的集合属性不是ObjectQuery
类型,而是EntityCollection
(但是,它有一种方法可以将它们转换为ObjectQuery
)。
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]
public sealed class EntitySet<TEntity> : IList,
ICollection, IList<TEntity>, ICollection<TEntity>, IEnumerable<TEntity>,
IEnumerable, IListSource
where TEntity : class