所以我最近發現,你可以強制實體框架不要將你的投影轉化爲SQL,只需要指定Func<T, TResult>
擴展爲.Select()
而不是表達式。當您想要轉換查詢的數據時,這很有用,但這種轉換應該發生在您的代碼而不是數據庫中。此擴展方法是否有效地實現了我的IQueryable?
例如,使用EF5新的枚舉支持,並試圖項目,要在DTO的字符串屬性,而這會失敗時:
results.Select(r => new Dto { Status = r.Status.ToString() })
這會工作:
results.Select(new Func<Record, Dto>(r => new Dto { Status = r.Status.ToString() }));
因爲在第一個(表達式)情況下,EF無法弄清楚如何將Status.ToString()轉換爲SQL數據庫可以執行的內容,但根據this article Func謂詞不會被轉換。
一旦我有這個工作,這是沒有太大的飛躍創造了下面的擴展方法:
public static IQueryable<T> Materialize<T>(this IQueryable<T> q)
{
return q.Select(new Func<T, T>(t => t)).AsQueryable();
}
所以我的問題是 - 是否有任何陷阱我應該警惕使用這種時候?是否會對性能產生影響 - 要麼將此無所作爲投影插入到查詢管道中,要麼導致EF不將.Where()
子句發送到服務器,從而通過線路發送所有結果?
意圖是仍然使用.Where()
方法來篩選服務器上的結果,但隨後.Select()
使用前.Materialize()
使提供者不試着翻譯投射到SQL Server:
return Context.Record
.Where(r => // Some filter to limit results)
.Materialize()
.Select(r => // Some projection to DTO, etc.);
看起來不錯。應在哪裏發送數據庫。但是,爲什麼不簡單使用'ToList()'而不是'Materialize'? –