2013-10-29 38 views
-1

我有最終導致具有string Qtystring SelectedQtyOperator從具有>==<=等的組合框形式,並且數據庫?intQty柱。我試圖找到一種方法來評估這個LINQ表達式內沒有寫每個選項的ifelse/switch語句。評估運算符號和執行操作員

目前我有:

data = data.Where(m => Convert.ToInt32(m.Qty) [somehow evaluate SlQtyOp] Convert.ToInt32(Qty)).Select(m => m); 

是否有可能做到這一點的表達裏面還是有一些類型的計算它,並適當表達輔助函數的?

編輯:

我忘了提data被初始化爲:

var data = db.MyDatabase.Select(m => m); 

其中db是一個DataContext

對於那些使用LINQ到對象和閱讀本

當我嘗試爲此在LINQ到SQL(我用我自己的疏忽最初沒有提及),吉姆·米契爾 & 斯利拉姆Sakthivel發佈不同,可能幫助您解決方案。

+0

在查詢語法中使用LINQ時,您可以使用[let子句](http://msdn.microsoft.com/zh-cn/library/vstudio/bb383976.aspx)來評估和存儲某些值以供以後使用查詢。 – pasty

+0

這裏使用'Select(m => m)'是什麼意思? – dasblinkenlight

+0

我認爲Select是需要的,即使它是爲所有人設計的,只是我自己學到的方式全是 – PRX

回答

1

沒有if-elseswitch,你不能做到這一點與LINQ,你需要Dyamic LINQ

1

一個處理,不需要使用額外的庫將在部分構建您的查詢任務的瑣碎辦法:啓動通過查詢表格並添加您可能具有的其他Where子句。在此之後,構造一個簡單switch聲明是這樣的:

IQueryable<MyDataType> data = ... // Put the initial query/table here 
var qty = Convert.ToInt32(Qty); 
switch (SelectedQtyOperator) { 
    case ">": data = data.Where(m.Qty > qty); break; 
    case "<": data = data.Where(m.Qty < qty); break; 
    case "==": data = data.Where(m.Qty == qty); break; 
    case ">=": data = data.Where(m.Qty >= qty); break; 
    case "<=": data = data.Where(m.Qty <= qty); break; 
    default: /* Throw an exception: this shouldn't happen */ break; 
} 
foreach (var d in data) { 
    ... 
} 
4

我會做這樣的事情:

bool IsLessThan(int a, int b) 
{ 
    return a < b; 
} 

bool IsGreaterThan(int a, int b) 
{ 
    return a > b; 
} 

以同樣的方式創建IsEqualIsLessEqualIsGreaterEqualIsNotEqual

,並創建一個委託:

Func<int, int, bool> comparisonFunc; 

而你所說的LINQ之前,您指定的委託:

switch (oper) 
{ 
    case "<" : comparisonFunc = IsLessThan; break; 
    case ">" : comparisonFunc = IsGreaterThan; break; 
    // etc. 
} 

你的LINQ表達式就變成了:

data = data.Where(m => comparisonFunc(m.Qty, Convert.ToInt32(Qty))).Select(m => m); 

現在,如果你的一些字段是int,有些是double等,那麼你的方法略有不同:

bool IsLessThan(int rslt) 
{ 
    return rslt < 0; 
} 

bool IsGreaterEqual(int rslt) 
{ 
    return rslt >= 0; 
} 

依此類推。您的委託是稍有不同:

Func<int, bool> comparisonFunc; 

並使用IComparer的輸入您的LINQ表達式:

data = data.Where(m => comparisonFunc(m.Qty.CompareTo(Convert.ToInt32(Qty)))).Select(m => m); 

或者,如果它是一個double

data = data.Where(m => comparisonFunc(m.Qty.CompareTo(Convert.ToDouble(Qty)))).Select(m => m); 

順便說一句在這種情況下,不需要Select。您沒有進行投影(即您正在拍攝對象),因此您可以消除Select

+1

您也可以定義一個'Dictionary >'來映射值一個'switch',我發現它有點乾淨,但概念是一樣的。 – Servy

+0

測試它,這在LINQ到對象中起作用,但是由於我在做LINQ到SQL(對不起,最初沒有提及),它沒有支持到SQL的轉換。不過謝謝。 – PRX

+0

@Servy:好點。我也會找到Dictionary清潔工。當時沒有想到它。 *聳聳肩* –

0

有可能做一些與反思我想,但像這樣的作品,以及:

switch (SlQtyOp) 
{ 
case ">": 
    data = data.Where(m => m.Qty > Convert.ToInt32(Qty)).Select(m => m); 
case "<": 
    data = data.Where(m => m.Qty < Convert.ToInt32(Qty)).Select(m => m); 
case "=": 
    data = data.Where(m => m.Qty = Convert.ToInt32(Qty)).Select(m => m); 
} 

這可能比較容易,只需使用交換機雖然。

+0

這正是我試圖避免XD的原因 – PRX

0

所以,鑑於這是一個IQueryable,而不是IEnumerable,你需要操縱表達式,而不是函數。首先,我們將定義有各運營商的字符串版本並將其映射到表示操作的表達詞典:可以添加

var mappings = new Dictionary<string, Expression<Func<int, int, bool>>>() 
{ 
    {">", (Expression<Func<int, int, bool>>)((a,b)=> a > b)}, 
    {"<", (Expression<Func<int, int, bool>>)((a,b)=> a < b)}, 
    {"==", (Expression<Func<int, int, bool>>)((a,b)=> a == b)}, 
}; 

等操作。

還有一個幫助器方法,我們將用它在整個表達式中用一個表達式替換另一個表達式的所有實例。

它使用該訪問者:

public class ReplaceVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public ReplaceVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 

而只是把它包裝在更清晰的語法:

public static Expression Replace(this Expression expression, 
    Expression searchEx, Expression replaceEx) 
{ 
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression); 
} 

從那裏,我們繼續前進的問題的肉,創建過濾器的操作一個給定的查詢,其中兩個給定的操作數使用給定的操作符進行評估。它將查詢過濾,每個操作數的選擇器,然後操作。然後它用操作數選擇器替換操作參數的所有實例,並用左邊的選擇器的參數替換正確的選擇器參數,以便在最終產品中有一個實際參數,然後將其包裝到lambda中並通過到Where

public static IQueryable<TIn> WhereOperator<TIn, TLeft, TRight>(
    this IQueryable<TIn> query, 
    Expression<Func<TIn, TLeft>> leftSelector, 
    Expression<Func<TIn, TRight>> rightSelector, 
    Expression<Func<TLeft, TRight, bool>> operation) 
{ 
    var newRightBody = rightSelector.Body.Replace(rightSelector.Parameters[0], 
     leftSelector.Parameters[0]); 
    var newOperator = operation.Body.Replace(operation.Parameters[0], leftSelector.Body) 
     .Replace(operation.Parameters[1], newRightBody); 
    var lambda = Expression.Lambda<Func<TIn, bool>>(newOperator, 
     leftSelector.Parameters[0]); 
    return query.Where(lambda); 
} 

用法示例:

IQueryable<Tuple<int, int>> query = new[] { Tuple.Create(1, 2) } 
    .AsQueryable(); 

var query2 = query.WhereOperator(pair => pair.Item1, pair => pair.Item2 
    , mappings[">"]); 

在我們使用的內存queryables這種情況下,但作爲query2.Expression會告訴你,這其實看起來與已經叫:

var query3 = query.Where(pair => pair.Item1 > pair.Item2);