2017-06-05 98 views
0

我正在使用泛型,因爲我需要大量的具有不同類型數據的可重用性。我的主要問題是查詢數據。我正在尋找一種方法來查詢是這樣的:對通用實體字段名稱的動態查詢

public void test<T>(int id, T type) where T : class 
{ 
    using (var ctx = myDbContext()) 
    { 
     var myTbl = ctx.Set<T>(); 
     //this line gets the primary key of the table 
     string key = myTbl.GetPrimaryKey(ctx); 

     //this is the query I want: 
     var myResult = myTbl.FirstOrDefault(x => x.key == id); 

     //let's say if key = "UserId", then (x => x.UserId == id) or something that translates to this. 
    } 
} 

也已實施了以下方法:

public object GetPropertyValue(object src, string propertyName) 

,我可以用它來獲取特定屬性的值。

但我的問題是,我不能在.FirstOrDefault()調用中使用它,因爲LINQ查詢方法的問題。

我目前使用此代碼來代替:

var myResult = myTbl.ToList().FirstOrDefault(x => (int)GetPropertyValue(x, key) == id); 

這是很好的與數據庫中的行數數,但在未來,當數據的增長將有很大的性能影響。

P.S:我使用的是EF電動工具的逆向工程代碼首先

+0

嗯,你的代碼樣本完全不清楚。請至少提供正確的變量名稱,因爲現在我甚至不知道你在哪裏使用'key'變量。 – eocron

+0

@eocron編輯。 'key'變量當前被傳遞給'GetPropertyValue()'方法。 –

回答

0

首先 - >不要使用myTbl.ToList().FirstOrDefault(x => (int)GetPropertyValue(x, key) == id),因爲它會生成一個選擇,它會從該表中獲取所有行,然後按內存中的id進行過濾。你應該將你的過濾器翻譯成一個Expression>,它將生成一個被Id列過濾的選擇。

建立你的LINQ表達式是這樣的:

var x = Expression.Parameter(typeof(T), "x"); 

string keyPropName = type.GetPrimaryKey(ctx); 
var equalExp = Expression.Equal(
    Expression.Property(x, keyPropName), 
    Expression.Constant(id) 
    ); 

var lambda = Expression.Lambda<Func<T, bool>>(equalExp, x); //x => x.Id == idValue 

var myResult = tbl.FirstOrDefault(lambda); 

我用你GetPropertyValueGetPrimaryKey方法。

+1

不錯的方法,但我想你錯過了'id'參數,而不是'Expression.Constant(GetPropertyValue(type,keyPropName))''我使用Expression.Constant(id)' –

+0

這是對的!!,我沒有看該參數。對不起,我會改變答案。 –

0

嗯,你的代碼示例是完全不清楚。請至少提供正確的變量名稱,因爲現在我甚至不知道你在哪裏使用'key'變量。另外,如果要存儲和查詢對象及其各種繼承和嵌套的屬性,請考慮使用NoSQL數據庫而不是基於關係的SQL引擎。