2009-10-21 69 views
1

我正在用SubSonic 3.0.0.3 ActiveRecord構建一個小型項目,我遇到了一個我似乎無法通過的問題。使用LINQ和SubSonic進行對象映射

這裏的LINQ查詢:

var result = from r in Release.All() 
      let i = Install.All().Count(x => x.ReleaseId == r.Id) 
      where r.ProductId == productId 
      select new ReleaseInfo 
      { 
       NumberOfInstalls = i, 
       Release = new Release 
       { 
        Id = r.Id, 
        ProductId = r.ProductId, 
        ReleaseNumber = r.ReleaseNumber, 
        RevisionNumber = r.RevisionNumber, 
        ReleaseDate = r.ReleaseDate, 
        ReleasedBy = r.ReleasedBy 
       } 
      }; 

的ReleaseInfo對象是自定義類,看起來像這樣:

public class ReleaseInfo 
{ 
    public Release Release { get; set; } 
    public int NumberOfInstalls { get; set; } 
} 

發行和安裝由亞音速生成的類。

當我對結果執行監視時,Release屬性爲null。

如果我使這個更簡單的查詢和觀察結果,值不爲空。

var result = from r in Release.All() 
      let i = Install.All().Count(x => x.ReleaseId == r.Id) 
      where r.ProductId == productId 
      select new Release 
      { 
       Id = r.Id, 
       ProductId = r.ProductId, 
       ReleaseNumber = r.ReleaseNumber, 
       RevisionNumber = r.RevisionNumber, 
       ReleaseDate = r.ReleaseDate, 
       ReleasedBy = r.ReleasedBy 
      }; 

這是我的LINQ查詢或SubSonic的限制問題嗎?

+0

您是否嘗試過使用更簡單的查詢來創建臨時變量(使用'let')構造您的ReleaseInfo對象之前? – 2009-10-22 00:24:35

+0

即使我將let部分帶出查詢,我也有同樣的問題。 – 2009-10-22 02:30:43

回答

1

我想我已經找到了這個問題的實際答案。我一直在SubSonic源代碼中搜索,發現將數據讀取器映射到對象時有兩種類型的對象投影:一種用於匿名類型和分組,另一種用於其他所有內容:

這是一段代碼片段:行269 - 298 SubSonic.Linq.Structure.DbQueryProvider

IEnumerable<T> result; 
Type type = typeof (T); 
//this is so hacky - the issue is that the Projector below uses Expression.Convert, which is a bottleneck 
//it's about 10x slower than our ToEnumerable. Our ToEnumerable, however, stumbles on Anon types and groupings 
//since it doesn't know how to instantiate them (I tried - not smart enough). So we do some trickery here. 
    if (type.Name.Contains("AnonymousType") || type.Name.StartsWith("Grouping`") || type.FullName.StartsWith("System.")) { 
    var reader = _provider.ExecuteReader(cmd); 
    result = Project(reader, query.Projector); 
    } else 
    { 
     using (var reader = _provider.ExecuteReader(cmd)) 
     { 
      //use our reader stuff 
      //thanks to Pascal LaCroix for the help here... 
      var resultType = typeof (T); 
      if (resultType.IsValueType) 
      { 
       result = reader.ToEnumerableValueType<T>(); 
      } 
      else 
      { 
       result = reader.ToEnumerable<T>(); 
      } 
     } 
    } 
    return result; 

的事實證明亞音速ToEnumerable試圖在DataReader的到對象你要投射到屬性相匹配的列名。從我的LINQ SQL查詢看起來是這樣的:

SELECT [t0].[Id], [t0].[ProductId], [t0].[ReleaseDate], [t0].[ReleasedBy], [t0].[ReleaseNumber], [t0].[RevisionNumber], [t0].[c0] 
FROM (
    SELECT [t1].[Id], [t1].[ProductId], [t1].[ReleaseDate], [t1].[ReleasedBy], [t1].[ReleaseNumber], [t1].[RevisionNumber], (
    SELECT COUNT(*) 
    FROM [dbo].[Install] AS t2 
    WHERE ([t2].[ReleaseId] = [t1].[Id]) 
    ) AS c0 
    FROM [dbo].[Release] AS t1 
) AS t0 
WHERE ([t0].[ProductId] = 2) 

公告的[T 0] [C0]是不一樣的我的屬性名稱NumberOfInstalls。所以c0的值永遠不會投影到我的對象中。

修正: 你可以簡單地取出if語句,並使用10倍慢的投影,一切都將工作。

1

我認爲這個問題可能是你基本上覆制了ORM的功能。瞭解事情的關鍵是這一行:

from r in Release.All() 

此行返回完全填充發行記錄列表數據庫中的每個項目。永遠不需要在查詢的其他地方新增發佈 - 只需返回SubSonic已經爲您填充的發佈即可!

使用這個邏輯,你應該能夠做到以下幾點:

var result = from r in Release.All() 
       select new ReleaseInfo { 
        Release = r, 
        NumberOfInstalls = Install.All().Count(x => x.ReleaseId == r.Id) 
       }; 

話雖這麼說,你應該看看Install.All()調用,因爲這很可能是極大的效率低下。這將做的是從數據庫中提取所有安裝,將這些安裝合併到對象中,然後比較.NET中每個記錄的ID以檢查記錄是否滿足該條件。您可以使用SubSonic中的.Find方法僅返回數據庫層的某些記錄,這應該有助於提高性能。即使如此,充氣物體可能仍然很昂貴,您可能想在這裏考慮一個視圖或存儲過程。但作爲一個簡單的第一步,下面應該工作:

var result = from r in Release.All() 
      select new ReleaseInfo { 
       Release = r, 
       NumberOfInstalls = Install.Find(x => x.ReleaseId == r.Id).Count() 
      }; 
+0

Release.All()返回一個IQueryable ...它將永遠不會擊中數據庫,直到它被枚舉。問題不在於查詢,而在於SubSonic將查詢結果映射到對象的方式。看看http://stackoverflow.com/questions/1655354/subsonic-3-0-and-linq/1670198#1670198的解決方案。 – 2009-11-03 22:02:09

0

我們有某些occassions該車次的預測中的錯誤 - 我認爲它經過修補,但我需要更多的測試。我邀請您嘗試最新的版本 - 我認爲我們已經修復了它......很抱歉如此模糊,但錯誤在3.0.0.1和3.0.0.3之間運行,我一直無法找到它。

+0

Rob,我正在使用3.0.0.3。如果您有興趣,我認爲我標記爲答案的帖子會向您顯示該錯誤所在的位置。感謝您花時間看看這個。 – 2010-01-20 06:45:29

-1

這已在3.0.0.4中修復?我非常喜歡這個帖子。經過2天的試圖找出爲什麼我的預測不起作用 - 除了當屬性名稱完全符合查詢 - 我最終在這裏。 我非常依賴SS SimpleRepository,現在回頭來不及了。像這樣的一個錯誤是癱瘓的。是否有機會整理出來?

我現在慢了10倍,所以我至少可以發佈給我的客戶。會更喜歡更快的方法正常工作:)

+0

它表示這個問題已在3.0.0.4發佈公告中得到解決,但截至今日,我仍然在使用該版本和最新的GitHub源代碼。 – 2010-06-24 17:35:24