2013-09-16 34 views
0

我正在建立我自己的反射函數爲某些類型的搜索。反射Linq實體「IN()」函數爲「包含」搜索整數組

問題是我想在ID列表中搜索一組ID,並過濾我的搜索/選擇查詢以僅包含這些特定對象。

這與在Linq-Entity框架中使用「IN()」相同。但我不能使用a.objid。

return query.Where(a => ObjectsToFind.Contains(a.objid)); 

但是,因爲我用t樣板 「a.objid」 導致錯誤。

所以a是「T a」而不是「MyTable a」,所以我可以稱它爲「objid」屬性。

我知道有一種方法可以用參數表達式來做到這一點。但是,我無法弄清楚。

這裏就是我試圖替換上述行:

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, string contains) 
{  
    var ObjectsToFind = new List<int>(); // I want to search IN() this function that gets filled in here. 
    ObjectsToFind = FillObjectsToFind(); // just the object id integers I want to filter 
    var parameter = Expression.Parameter(typeof(T), "type"); 
    var propertyExpression = Expression.Property(parameter, "objid"); // I look for this 
    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(int) }); // int type 
    var vars = Expression.Variable(List<int>,); // I can't use "constant", but what do I use here? 
    var containsExpression = Expression.Call(propertyExpression, method, vars); 
    return query.Where(Expression.Lambda<Func<T, bool>>(containsExpression, parameter)); 
} 

更換「T」與實際表實體,會導致很多的問題,所以我決定保持T.


else if (s.ST == "function") 
{ // search func 
    myTable a; 
    DC2 = MyUtility.WhereFunctionContains(DC2, a => a.objid, s.S); 
    // s.S is my search query string. 
    // s.ST means I'm searching for functions (from another associated table) 
    // I don't understand how a.objid gets called, I wanted to use Template/Reflections. 
} 

下面是我如何調用Zev的函數。

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, Expression<Func<T, int>> converter, string contains) 
{ 
    FunctionsClass fc = new FunctionsClass(); 
    var ObjectsToFind = new List<int>(); 
    ObjectsToFind = fc.SearchContainFunction(contains); // I grabbed my list of IDs to search 
    return query.Where(t => ObjectsToFind.Contains(converter(t))); 
} 
+0

你可以在你的問題中包含什麼類型的ObjectsToFind? – EkoostikMartin

+2

'因爲我使用T模板而導致錯誤',這是因爲你的'template'錯過了一些限制信息,比如使用'where T:...' –

+0

ObjectsToFind ===> List () – Dexter

回答

2

如果我理解正確的話,你有許多查詢在不同類型的:

IQueryable<Person> personsQry = ... 
IQueryable<Sale> salesQry = ... 
IQueryable<Order> ordersQry = ... 

,你必須生成一個List<int>的方法,叫FillObjectsToFind

public List<int> FillObjectsToFind() 
{ 
    //code here 
} 

您希望能夠限制每個上述查詢,只有返回列表中的ID。作爲額外的獎勵,這應該是一個擴展方法,所以你可以這樣調用:

var personsFiltered = personsQry.WhereFunctionContains(...); 
var salesFiltered = salesQry.WhereFunctionContains(...); 
var ordersFiltered = ordersQry.WhereFunctionContains(...); 

的問題是每個查詢是一個單獨的類型,你會喜歡寫,涵蓋所有的一種方法他們。


解決方案的第一部分是定義一個通用的方法:

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query) 
{ 
    //code here 
} 

但仍有一個問題:我們知道的唯一一種是類型T這是不是一個真正的類型,但對於一個佔位符實際類型。由於這些類型可能是任何東西 - string,System.Random,SqlConnection,ASP.NET Label,WPF TextBlock-無法知道如何將每個對象與Listints進行比較。


最直截了當的方法是定義一個 接口

interface IHasObjID 
{ 
    int ObjID {get;set;} 
} 

然後每一類都應該實現此接口:

class Person : IHasObjID 
{ 
    int objID; 
    int ObjID 
    { 
     get {return objID;} 
     set {objID = value;} 
    } 
} 

//implement sales and orders similarly 

一旦做到這一點,你可以定義一個約束該方法允許的類型。現在,類型肯定有一個ObjID屬性,我們可以對查詢:

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query) where T : IHasObjID 
{ 
    var intsToFind = FillObjectsToFind(); 
    return query.Where(t => intsToFind.Contains(t.ObjID)); 
} 

這是景景告訴你this評論。


我建議調用此函數時,你也傳遞了如何在從類型整數得到:

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, Expression<Func<T,int>> converter) 
{  
    var intsToFind = FillObjectsToFind(); 
    return query.Where(t => intsToFind.Contains(converter(t))); 
} 

不過,我還沒有測試此代碼,因爲我們正在努力使用實體框架和表達式我懷疑仍然存在一個問題:表達式不能在表達式中「調用」。 我想提出上述,但它不與下面的錯誤編譯 - 「轉換器」是一個「變量」,但就像一個「方法」使用。

畢竟是,該解決方案是簡單的,採用Join

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, Expression<Func<T,int>> converter) 
{ 
    var ints = new List<int>() { 1, 2, 3, 4, 5 }; 
    return query.Join(ints,converter,i=>i,(t,i) => t); 
} 

被稱爲像這樣:

var filteredPersons = query.WhereFunctionContains(p => p.PersonID); 


如果這是僅使用單一類型的 MyTable使用:

public static IQueryable<MyTable> WhereFunctionContains(this IQueryable<MyTable> query) 
{ 
    var ints = new List<int>() { 1, 2, 3, 4, 5 }; 
    return query.Join(ints, mt=>mt.objid, i=>i, (t,i) => t); 
} 


C# Programming Guide某些鏈接(在答題的順序排列):

另外,請參閱here的LINQ運營商的一個很好的概述,如SelectWhereCountToList

+0

將不會爲實體框架工作,因爲這將在內存中執行(由於'Func'而不是'表達式' –

+0

另外我怎樣才能調用這個函數呢?請提供一個例子以及函數。知道轉換器是什麼樣的) – Dexter

+0

@DarrenKopp編輯。使用'Expression '它能工作嗎?因爲'List '存在本地,而不是在數據庫上。另外,可能不允許調用'converter'。在這種情況下,我會建議使用['PredicateBuilder'](http://www.albahari.com/nutshell/predicatebuilder.aspx),迭代列表併爲列表中的每個項目的謂詞添加一個「Or」子句 –