2009-09-23 60 views
6

我無法解決某些dbml生成的類無法解析爲高效的SQL。想象一下,我有一個帳戶表和一個交易表,每個交易都與一個特定的帳戶相關聯。我將所有這些加載到dbml中,然後彈出一個Account類和一個Transaction類。 Account類具有一個EntitySet對一組交易的引用,它表示該賬戶上的所有交易。很公平。LINQ to SQL實體集中的抽象抽象

現在假設我只想要當前會計期間的交易。所以,我想補充的方法是這樣的:

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對象。我已經嘗試去掉where子句,orderby子句,用常量代替日期,但它仍然在客戶端完成。

爲了便於比較,我想直接調用交易收集掉數據方面:

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] 

畢竟是這樣,我有兩個問題:

  1. 交易實體集的上述行爲是否正確和/或是否有解決方法?
  2. 如何在帳戶類中實現上述「修復」作爲方法。由dbml生成的實體類無權訪問DataContext。

回答

6

不幸的是,您不能那樣做。爲LINQ to SQL實體類生成的集合屬性不是IQueryable;因此,對它們執行的任何查詢都將使用LINQ to Objects。這是設計。正如你正確地注意到自己,要獲得高效的查詢,你必須查詢Transactions取自DataContext,但你的財產gettor中沒有。

在這一點上你的選擇要麼是:

  • 使它成爲這需要一個DataContext作爲參數的方法;或
  • 使用反射兩輪牛車以檢索上下文 - 實體本身不存儲,但EntitySet S於它做的,儘管是間接的 - 當然,這是特定的版本,容易破損等

到目前爲止據我所知,實體框架沒有這個限制,因爲它的集合屬性是ObjectQuery<T> - 這是IQueryable

+0

實體框架的集合屬性,至少從2009年到現在,不是「ObjectQuery 」類型,而是類型爲「EntityCollection 」(但它有一種將它們轉換爲「ObjectQuery 」的方法)。 – 2013-03-21 16:03:08

0

從使用IEnumerable開始切換到IQueryable,而您的SQL將被優化爲僅根據需求提供所需內容。

+1

它不會。他的問題是'Transactions'不是'IQueryable',他不能做任何事情(它是一個'EntitySet',並且必須保持爲1)。 – 2009-09-23 23:36:36

+0

是的,這正是問題所在。 – 2009-09-23 23:39:30

+0

Argh。從來不是一個簡單的解:) – 2009-09-23 23:42:28

3

什麼是類型的交易第一個例子?

請記住,您正在使用擴展方法。所使用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 

回答您的問題:

  1. 交易沒有實現IQueryable的<牛逼>所以這是正確的行爲
  2. 您的帳戶類將需要能夠引用交易表對象
+0

事務是dbml生成的EntitySet屬性。 \t \t [協會(名稱= 「Account_Transaction」,存儲= 「_事務」,ThisKey = 「ID」,OtherKey = 「ACCOUNT_ID」)] \t \t公共的EntitySet 交易 – 2009-09-23 23:38:55

+0

關於2)。我明白這一點,問題是如何獲得這樣的參考,因爲Account對象通常是由數據上下文/實體框架創建的?我將在哪裏接入賬戶對象,以引用交易表?換句話說,給定一個與特定數據上下文關聯的實體對象,我該如何從該實體返回它的數據上下文? – 2009-09-23 23:50:21

+0

您正在擴展Account對象的功能嗎?添加一個參數化的方法調用? IEnumerable GetCurrentTransactions(DataContext ctx) – 2009-09-23 23:56:31