2016-09-22 71 views
2

我有一個複雜的對象,其中有很多孩子,我只想從中選擇一些屬性,並在子網中顯示其子元素。之前的查詢結構的方式是在每個需要的.Include()中盲目折騰,生成一條1095行長的SQL語句。Casting a Select從屬性集合中的.Last()中獲取屬性

我沒有問題從一個子對象獲取單個屬性,但是一個是最後一次執行的活動的名稱。在集合上執行.Last().Name會拋出異常,無法將其轉換爲SQL。我將做一個簡單的例子,以幫助可視化(所有FKS都在我的代碼實際設置,這不是問題):

public class Foo 
{ 
    public int Id { get; set; } 
    // just a dummy class everyone knows for illustration 
    public Address Address { get; set; } 
    public ICollection<Activity> Activities { get; set; } 
} 

public class Activity 
{ 
    public string Name { get; set; } 
} 

public class FooModel 
{ 
    public int Id { get; set; } 
    public string StreetName { get; set; } 
    public string LastActivity { get; set; } 
} 

這是我設置了查詢的一個基本的例子:

public IEnumerable<FooModel> GetHomePageItems(IEnumerable<int> fooIds) 
{ 
    return await context.Foos 
         .Where(f => fooIds.Contains(f.id)) 
         .Select(f => new FooModel 
          { 
           Id = f.Id, 
           StreetName = f.Address.Street, 
           // here is the problem as it can't 
           // convert this to SQL 
           LastActivity = f.Activities.Last().Name 
          }) 
         .ToListAsync(); 
} 

這是一件拄着柺杖的工作,還是我不得不在沒有LastActivity的情況下將所有東西拉開,然後用GroupBy查詢活動並以這種方式獲取它們?

回答

3

你可以試着改變你的查詢:

var query = context.Foos 
       .Where(f => fooIds.Contains(f.Id)) 
       .Select(f => new FooModel 
       { 
        Id = f.Id, 
        StreetName = f.Address.Street,  
        LastActivity = f.Activities.OrderByDescending(x => x.Id).FirstOrDefault().Name 
       }).ToListAsync(); 

這LINQ生成以下SQL的實體框架版本6.1.3:

SELECT 
    [Filter1].[Id1] AS [Id], 
    [Filter1].[Street] AS [Street], 
    [Limit1].[Name] AS [Name] 
    FROM (SELECT [Extent1].[Id] AS [Id1], [Extent2].[Street] AS [Street] 
     FROM [dbo].[Foos] AS [Extent1] 
     LEFT OUTER JOIN [dbo].[Addresses] AS [Extent2] ON [Extent1].[Address_Id] = [Extent2].[Id] 
     WHERE [Extent1].[Id] IN (1, 2, 3, 4)) AS [Filter1] 
    OUTER APPLY (SELECT TOP (1) [Project1].[Name] AS [Name] 
     FROM (SELECT 
      [Extent3].[Id] AS [Id], 
      [Extent3].[Name] AS [Name] 
      FROM [dbo].[Activities] AS [Extent3] 
      WHERE [Filter1].[Id1] = [Extent3].[Foo_Id] 
     ) AS [Project1] 
     ORDER BY [Project1].[Id] DESC) AS [Limit1] 

這可能是足以讓你的項目。但是,對於大量數據,您可能需要更快地切換到某些內容,甚至可能需要使用.Sql()方法進行手動查詢。

實體框架不承認.LastOrDefault().Last()方法,而應該使用.FirstOrDefault().First()方法加上OrderBy()OrderByDescending()

+0

優秀!我會在早上試試。 – krillgar

+0

Huzzah!有效。謝謝你,先生。在昨天結束的恐慌中,我忘記了讓它更像這樣「冗長」。 (爲了記錄,這把查詢減少到54行。) – krillgar

+0

@krillgar很高興它爲你工作得很好! :) –