2017-09-11 37 views
0

考慮下面的對象圖有條件排除子屬性,實體框架查詢

public class Bar { 
    public Guid Id {get;set;} 
    public string SomeBar {get;set;} 
} 

public class Foo { 
    public Guid Id {get;set;} 
    public string FooString {get; set;} 
    public IList<Bar> Bars {get;set;} 
} 

如何有條件地適當地排除Bars屬性,使實體框架不會加載整個對象圖?

// my thoughts 
public Task<Foo> GetFooByIdAsync(Guid id, bool includeBars) 
{ 
    var query = _db.Foos.Where(f => f.Id == id); 
    if(!includeBars) 
    { 
     return query.Select(f=> new Foo{ 
      Id = f.Id, 
      FooString = f.FooString 
     }).ToListAsync(); 
    } else { 
     return query.ToListAsync(); 
    } 
} 
+0

你有沒有看到這個帖子:https://stackoverflow.com/questions/3718400/conditional-eager-loading? –

+0

@DavidTansey有很多帖子要過濾,如果你沒有得到正確的搜索詞,他們不會出現。不,我沒有看到那個。基於這個答案,我認爲只要你foreach迭代iqueryable,它會加載數據,這是正確的嗎?還有,不同於調用'.Select(f => ...);'在我的例子中? –

+1

對不起 - 我沒有注意到你在你的問題中顯示了一個可行的方法。就鏈接帖子中的'foreach'與您的代碼而言,我對此的理解完全符合您所描述的內容。我唯一要補充的是:如果在比較看似等價的語法時,如果您的問題/情況進一步擴展爲與性能相關的問題 - 請花時間使用SQL事件探查器檢查生成的查詢,看看它們是否真的是等效的。 EF有時會生成「有趣」的SQL。 –

回答

2

只是有條件地在查詢表達式中添加Include(f => f.Bars)。就像這樣:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations.Schema; 
using System.Data.Common; 
using System.Data.Entity; 
using System.Data.Entity.ModelConfiguration; 
using System.Data.SqlClient; 
using System.Linq; 
using System.Threading.Tasks; 


namespace ConsoleApp8 
{ 
    public class Bar 
    { 
     public Guid Id { get; set; } 
     public string SomeBar { get; set; } 
    } 

    public class Foo 
    { 
     public Guid Id { get; set; } 
     public string FooString { get; set; } 
     public IList<Bar> Bars { get; set; } 
    } 

    class Db: DbContext 
    { 

     public DbSet<Foo> Foos { get; set; } 
     public DbSet<Bar> Bar { get; set; } 

     public async Task<Foo> GetFooByIdAsync(Guid id, bool includeBars) 
     { 
      var query = (IQueryable<Foo>)Foos.AsNoTracking(); 

      if (includeBars) 
      { 
       query = query.Include(f => f.Bars); 
      } 

      query = query.Where(f => f.Id == id); 

      var results = await query.ToListAsync(); 

      return results.FirstOrDefault();    
     } 
    } 



    class Program 
    {  

     static void Main(string[] args) 
     { 

      Database.SetInitializer(new DropCreateDatabaseAlways<Db>()); 


      using (var db = new Db()) 
      { 
       db.Database.Initialize(false); 
       db.Database.Log = m => Console.WriteLine(m); 

       var r1 = db.GetFooByIdAsync(Guid.Empty, false).Result; 
       var r2 = db.GetFooByIdAsync(Guid.Empty, true).Result; 

      } 
      Console.WriteLine("Hit any key to exit"); 
      Console.ReadKey(); 


     } 
    } 
} 

輸出

Opened connection asynchronously at 9/11/2017 11:37:26 PM -05:00 

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[FooString] AS [FooString] 
    FROM [dbo].[Foos] AS [Extent1] 
    WHERE [Extent1].[Id] = @p__linq__0 


-- p__linq__0: '00000000-0000-0000-0000-000000000000' (Type = Guid, IsNullable = false) 

-- Executing asynchronously at 9/11/2017 11:37:26 PM -05:00 

-- Completed in 22 ms with result: SqlDataReader 



Closed connection at 9/11/2017 11:37:26 PM -05:00 

Opened connection asynchronously at 9/11/2017 11:37:26 PM -05:00 

SELECT 
    [Project1].[C1] AS [C1], 
    [Project1].[Id] AS [Id], 
    [Project1].[FooString] AS [FooString], 
    [Project1].[C2] AS [C2], 
    [Project1].[Id1] AS [Id1], 
    [Project1].[SomeBar] AS [SomeBar] 
    FROM (SELECT 
     [Extent1].[Id] AS [Id], 
     [Extent1].[FooString] AS [FooString], 
     1 AS [C1], 
     [Extent2].[Id] AS [Id1], 
     [Extent2].[SomeBar] AS [SomeBar], 
     CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] 
     FROM [dbo].[Foos] AS [Extent1] 
     LEFT OUTER JOIN [dbo].[Bars] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Foo_Id] 
     WHERE [Extent1].[Id] = @p__linq__0 
    ) AS [Project1] 
    ORDER BY [Project1].[Id] ASC, [Project1].[C2] ASC 


-- p__linq__0: '00000000-0000-0000-0000-000000000000' (Type = Guid, IsNullable = false) 

-- Executing asynchronously at 9/11/2017 11:37:26 PM -05:00 

-- Completed in 2 ms with result: SqlDataReader 



Closed connection at 9/11/2017 11:37:26 PM -05:00 

Hit any key to exit 
+0

看,我的印象是,如果沒有明確排除,EF會自動加載連接。如果您在'.ToListAsync()'之前請求數據,情況是否如此? –

+1

是的。請參閱https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx –