2014-12-05 49 views
0

我正在使用WebAPI和實體框架來構建指向大型MSSQL數據庫(〜200個表)的REST API。數據庫非常規範化,因此檢索對API使用者有用的值需要大量的深入表格。實體框架/ LINQ - 從大型嵌套實體數據集返回數據傳輸對象

爲了向用戶返回有用的數據,我採用了使用工廠模式構建模型(或DTO)的方法。但是,我注意到即使所有數據都以良好的格式返回,由於啓用了延遲加載,仍然存在性能問題。簡而言之,即使在我只返回我需要的數據時,我仍然在查詢太多的數據。

於是我使出關閉延遲加載,並試圖搶在數據顯式地使用包括如下的方法:

var accessions = db.AccessionParties 
    .Include(ap => ap.Accession.AccessionParties.Select(ap2 => ap2.Party)) 

    .Include(ap => ap.Accession.AccessionParties.Select(ap2 => ap2.AccessionPartyPurposes.Select (app => app.PartyAccessionPurposeType))) 

    .Include(ap => ap.Accession.AccessionAnimals.Select(x => x.AnimalInformationType)) 

    .Include(ap => ap.Accession.AccessionAnimals.Select(x => x.Specimens.Select(y => y.AccessionTestRequestSpecimens.Select(z => z.AccessionTestRequest.LabTestOffering.TestOffering)))) 

    .ToList() 
    .Select(a => modelFactory.CreateAccessionModel(a.Accession)); 

下面是工廠方法我使用生成模型,其中包括一個例子嵌套的工廠方法以及塑造我的相關數據實體。

public AccessionModel CreateAccessionModel(Accession accession) 
    { 
     return new AccessionModel() 
     { 
      AccessionKey = accession.AccessionKey, 
      SubmittedDate = accession.SubmittedDate, 
      Parties = accession.AccessionParties 
           .Select(accessionParty => new { accessionParty = accessionParty, accessionParty.Party }) 
           .Select(accessionParty => CreatePartyModel(accessionParty.Party)), 
      Animals = accession.AccessionAnimals.Select(accessionAnimal => CreateAccessionAnimalModel(accessionAnimal)) 
     }; 
    } 

有沒有處理上述情況的模式或做法?我見過一些方法的例子,它允許你傳入一個包含語句的數組,但是我想不出一種以優雅,高效,實用的方式處理這個問題的方法。任何輸入將不勝感激。

回答

0

您可以使用automapper在實體和DTO之間進行映射,並與Projection一起執行查詢並只加載您的DTO需要的列。檢查http://automapper.org/https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions

希望有所幫助。

+0

謝謝奧馬爾。由於我在觀看演示者建議不使用AutoMapper進行ASP WebAPI項目的教程,因爲在我的模型中顯示自定義數據時可能會出現一些限制,所以我最初對使用AutoMapper猶豫不決。但是,現在我正在給AutoMapper拍攝一筆虧損。 – 2014-12-07 15:30:04

+0

與AutoMapper一起。到目前爲止,它對我所需要的工作非常有效。 – 2014-12-18 18:19:54

0

我這樣做是我的方法,通過在像這樣的字符串數組一個(它是醜陋的,因爲我使用反射來獲取屬性名稱,但希望你的想法)

private IQueryable<T> AddIncludes<T>(IDatabase db) // my Entity context class implements IDatabase 
{ 
    var props = typeof(IDatabase).GetProperties(BindingFlags.Public|BindingFlags.Instance); 
    IQueryable<T> ret = null; 
    foreach (var prop in props) 
    { 
     if (prop.PropertyType.Name == "IDbSet`1" && 
     prop.PropertyType.GetGenericArguments()[0] == typeof(T)) 
     { 
      ret = (IQueryable<T>)prop.GetValue(db, null); 
      break; 
     } 
    } 
    var includes = GetIncludes((DbContext)db, typeof(T)); // this returns an IEnumerable<string> of the includes 
    foreach (string include in includes) // replace string with a lambda 
    { 
     ret = ret.Include(include); // this is where the includes are added 
    } 
    return ret; 
} 

private ICollection<T> LoadObjectGraph<T>(IDatabase db, Func<T, bool> filter) 
{ 
    var queryableWithIncludesAdded = AddIncludes<T>(db); 
    return queryableWithIncludesAdded.Where(filter).ToList(); 
} 

代替使用字符串,您可以使用相同的技術來傳遞lambdas來構建您的查詢

+0

感謝您的迴應!我會給這個鏡頭... – 2014-12-06 03:35:17

+0

我選擇了奧馬爾的答案作爲我的迴應。 Automapper似乎有助於快速完成任務,我希望這是一個長期的解決方案。謝謝! – 2014-12-18 18:19:25