2009-10-31 117 views
3

我亞音速3.0 SimpleRepository玩耍,並試圖讓菜單和的菜單項與一個LINQ查詢,但的菜單項是空永諾亞音速3.0和LINQ

菜單

public class Menu 
{ 
    public Menu() 
    { 
     MenuId = 0; 
     MenuName = ""; 
     MenuItems = null; 
    } 
    public int MenuId { get; set; } 
    public string MenuName { get; set; } 
    public MenuItem MenuItems { get; set; } 
} 

菜單項

public class MenuItem 
{ 
    public MenuItem() 
    { 
     MenuItemId = 0; 
     MenuId = 0; 
     MenuItemName = ""; 
    } 
    public int MenuItemId { get; set; } 
    public int MenuId { get; set; } 
    public string MenuItemName { get; set; } 
} 

Linq查詢

var menus = from m in _repo.All<Menu>() 
      from mi in _repo.All<MenuItem>() 
      where m.MenuItems.MenuItemId == mi.MenuItemId 
      select new Menu 
      { 
       MenuId = m.MenuId, 
       MenuName = m.MenuName, 
       MenuItems = { 
          MenuItemId = mi.MenuItemId, 
          MenuItemName = mi.MenuItemName 
         } 
      }; 

有人能告訴我我在做什麼錯嗎?

回答

2

我想我已經找到了這個問題的實際答案。我一直在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倍慢的投影,一切都將工作。

+0

它是:「if(type.Name.Contains(」AnonymousType「)」還是它:「if(resultType.IsValueType)」需要放出? – 2009-11-04 09:04:09

+0

if(type.Name.Contains(「 AnonymousType「)|| type.Name.StartsWith(」Grouping「)... that line。 – 2009-11-04 17:38:18

+0

這是否解決了您的問題? – 2009-11-20 09:41:26

1

我不認爲你在這裏做錯了什麼。這似乎是Subsonic 3.0的一個問題。我現在有一個問題,我沒有得到here的答案。我最近也嘗試了一些更簡單的方法。但那也行不通。

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, 
       Id = r.Id, 
       ProductId = r.ProductId, 
       ReleaseNumber = r.ReleaseNumber, 
       RevisionNumber = r.RevisionNumber, 
       ReleaseDate = r.ReleaseDate, 
       ReleasedBy = r.ReleasedBy 
      }; 

已安裝財產的數量沒有得到填充,但是如果我映射到一個匿名類型一切正常:

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

如果你改變你的代碼如下它可能會工作:

var menus = from m in _repo.All<Menu>() 
      from mi in _repo.All<MenuItem>() 
      where m.MenuItems.MenuItemId == mi.MenuItemId 
      select new 
      { 
       MenuId = m.MenuId, 
       MenuName = m.MenuName, 
       MenuItems = new { 
          MenuItemId = mi.MenuItemId, 
          MenuItemName = mi.MenuItemName 
         } 
      }; 

由於您想要映射回預定義的對象類型,因此這種方式失敗了。也許我們可以從Rob那裏得到答案嗎? :)

+0

因爲我使用的DDD模式,我從我的服務層的方法返回一個對象,我根本不能使用匿名類型。唯一能解決的問題是遍歷我所有的manuitems,緩存它們(只打一次數據庫)並將它們添加到菜單對象中。 – 2009-11-03 18:51:12