2011-02-18 31 views
2

我有以下代碼來查詢的EntityContext(通過庫)並將其映射對一個DTO:調用內部的IQueryable的選擇DTO翻譯

public class QueryQuestionsConsumer : IConsumerOf<QueryQuestionsRequest> 
{ 
    public void Consume(QueryQuestionsRequest request) 
    { 
     var repo = IoC.Resolve<IUnitOfWork>().CreateRepository<Question>(); 
     var filter = FilterTranslator.CreateFilterExpression<Question>(request.Filters); 
     var questions = repo 
      .GetAll() 
      .Where(filter) 

     Result = questions.Select(question => QuestionTranslator.ToDTO(question)).ToArray() 
    } 

} 

這顯然會失敗,因爲ToDTO()不是在EntityFramework提供者中被識別的功能。我可以使用對象初始值設定項創建一個DTO對象,但我想將它委託給另一個類(QuestionTranslator)。

你在這種情況下做什麼?

更新: 此外,我不想水合一個完整的問題對象來做到這一點。我想指望提供者創建DTO對象的能力。

回答

3

除了使用questions.AsEnumerable().Select(...)強制EF檢索完整記錄,然後映射它們的客戶端的明顯的選擇,你可以讓你的ToDTO方法返回一個表達式:

Expression<Func<Question, QuestionDTO>> ToDTO() 
{ 
    Expression<Func<Question, QuestionDTO>> exp = 
     question => new QuestionDTO { ... }; 
    return exp; 
} 
+0

簡單而快速。無法要求更多。 – 2011-02-18 11:07:42

+0

如果您的查詢尚未評估,則可能會導致發生異常,並且提供程序不支持實例化新對象。 – smartcaveman 2011-02-18 15:12:25

+1

@smartcaveman他表示他正在使用EF,這是。 – 2011-02-18 15:16:34

1

你可以將其轉換爲可枚舉,然後在本地進行翻譯:

Result = questions.AsEnumerable() 
        .Select(question => QuestionTranslator.ToDTO(question)).ToArray() 

這將導致查詢被轉換到(本地)枚舉,它可以通過你的QuestionTranslator安全地通過。

+0

謝謝里德。因爲你的回答,我覺得有必要更新這個問題。感謝您的嘗試。 – 2011-02-18 10:56:22

0

我使用AutoMapper從實體到DTO的地圖,因爲如果你創建Question一個映射,然後它會自動知道如何地圖IEnumerable<Question>

的問題,在一個聲明中這樣做無論是查詢和映射的是它往往會導致你的數據映射器很難破譯錯誤發生時的錯誤(很難判斷問題出在查詢執行還是映射中)

我發現按照「激發」查詢要容易得多做一個.ToList()/.AsEnumerable()等,然後將該變量傳遞給映射器。這樣可以在問題發生時使異常非常清晰,從而明確問題是在查詢中還是在映射中。

0

看到這篇文章:Autoprojecting LINQ queries

當你使用它,你的查詢會像:

 Result = questions.Project().To<QuestionDto>().ToArray() 

應在服務器上,如果使用NHibernate/EF(發送到DB只需將投影屬性查詢)發生。對於在內存中讀取的對象(LINQ To Objects),仍然應該正常工作。