2009-05-19 64 views
3

首先,讓我道歉以免標題無意義。我很難理解我在做什麼,更不用說能夠用正確的詞來描述我在做什麼。對IQueryable執行.Select()與Func列表<T, string>代表

我建立我在其中一個頭/ LINQ表達式組合定義列通用的網格類:

public class Column<T> 
{ 
    public string Header { get; set; } 
    public Func<T, string> ValueExpression { get; set; } 
} 

用法:

Columns = new List<Column<Employee>> 
       { 
        new Column<Employee> {Header = "Employee Id", ValueExpression = e => e.EmployeeID.ToString()}, 
        new Column<Employee> {Header = "Name", ValueExpression = e => e.FirstName + " " + e.LastName}, 
        new Column<Employee> {Header = "Employee Birthday Year", ValueExpression = e => e.BirthDate.HasValue ? e.BirthDate.Value.Year.ToString() : ""} 
       }, 

我想要表現的ValueExpression的(Func<T, string> )在一個IQueryable, '僱員':

var db = new NorthwindDataContext(); 
var employees = db.Employees.Select(e => e); 

我可以得到而從員工中提取IEnumerable<IEnumerable<string>>這樣的(在我的觀點中使用字符串列表的列表)的工作:

var elementsList = employees.ToPagedList(PageIndex, PageSize); 
var elementStringList = elementsList.ToStringList(Columns.Select(c => c.ValueExpression).ToArray()); 

不介意PagedList的東西,這是無關緊要的,還挺一樣ToList();

這裏的ToStringList()擴展方法:

public static IEnumerable<IEnumerable<string>> ToStringList<T>(this IPagedList<T> enumerable, params Func<T, string>[] fields) 
{ 
    foreach (var element in enumerable) 
     yield return element.ToStringList(fields); 
} 

private static IEnumerable<string> ToStringList<T>(this T element, params Func<T, string>[] fields) 
{ 
    foreach (var field in fields) 
     yield return field(element); 
} 

的問題是,這種方法涉及指定必須返回的字段之前執行的IQueryable。

結果,下面的查詢得到沿途某處被執行:

SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], [t0].[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Extension], [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath] 
FROM [dbo].[Employees] AS [t0] 

正如你可能身影,這是不希望以從表中檢索員工的所有字段。

我正在尋找一種方法來在IQueryable員工上以某種方式構建擴展方法,在該方法中,我可以傳遞Func列表(「ValueExpression」列的成員)和「構建」一種新的IQuerable方式,即將執行剛剛從數據庫中檢索所需字段的SQL。

所以我在尋找這樣的事情:提前

IQueryable employees = employees.SelectByExpressions(Columns.Select(c => c.ValueExpression).ToArray()); 

感謝。

回答

0

我不知道我完全理解你想要做什麼,但它看上去非常像Predicate Builder

如果沒有它可以幫助您在正確的方向得到...

+0

謝謝,從來沒有聽說過它。該頁面上有很多示例代碼,所以我可能會在那裏找到我需要的。今天晚上會檢查一下。 – 2009-05-20 06:40:11

+0

我不相信Predicate Builder會做你想做的。它是關於動態構建謂詞(即Where子句),而您試圖動態構建Select語句。 – 2009-05-21 15:17:16

0

你看過Dynamic Linq嗎?我相信它會做你正在嘗試做的事情。

如果你有列作爲字符串,那麼你可以用這個做你的選擇謂語,它只會在被執行的SQL這些列。

+0

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx – 2009-05-21 15:28:01

1

,你會碰到的基本問題是,選擇必須返回某種類型的對象,但你想要的類型有根據已生成的動態查詢不同的領域。當您使用匿名類型時,編譯器會爲您生成一個具有相應字段的類型。但就你而言,在編譯時你不知道字段列表是什麼樣的,所以你不能讓編譯器爲你生成類型。

雖然它肯定是可以動態建立一個類型,將只包含您需要的領域,我必須停止,並質疑這是否是必要的。使用O/R映射器(如LINQ-to-SQL,尤其是與DataSets相反)的一部分理由是,維護在不同時間動態返回不同字段集的代碼的代價並不值得您從查詢中獲得的少量節省或從內存使用。事實上,在某些情況下,甚至會使查詢性能變差,因爲數據庫服務器無法使用不同字段列表優化多個查詢,這與使用相同字段列表優化多個查詢的方式相同。

另一種選擇,簡直是始終返回所有的字段,但只顯示所選擇的領域。這肯定會更簡單,更容易維護。但是,如果您已經測量了該解決方案的性能影響並確定它不符合您的要求,那麼您當然可以考慮動態生成必要的類型。如果您需要該解決方案的幫助,我可能會爲您處理一個樣本。但如果我是你,我肯定會確定我需要沿着這條路走下去,然後纔開始朝這個方向發展。

UPDATE:這裏的另一個問題是,你與這些查詢唯一的目標是否會在網格,或一些其他類型的動態綁定界面來顯示它們。如果是這樣的話,那麼使用一種「屬性包」解決方案可能就很容易,其中沒有涉及特定字段的具體類型,而只是用於鍵/值對的容器,類似於DataRow 。但是,如果您嘗試動態創建將在代碼中操作的類型,我強烈建議不要這樣做。技術實施可能很有趣,但維護很快就會變成一場噩夢。我一直被迫保持這樣的應用程序,如果我有選擇,我永遠不會再次。

相關問題