2011-06-23 21 views
5

私はシステムを実装することを考えています。それは、 'ビルド'条件を使用して、結果のデータをデータベースから返すことです。現在、オンザフライでSQLを生成して実行するストアドプロシージャがあります。これは私が削除したい特定の問題です。複数の/未知の基準を持つ動的linqクエリ

私の条件は、私の基準内に複数のフィールドを持つことができるという事実から来ています。これらの各フィールドには、異なる可能性のある演算子を持つ1つ以上の値があります。例えば、

from t in Contacts 
where t.Email == "[email protected]" || t.Email.Contains ("mydomain") 
where t.Field1 == "valuewewant" 
where t.Field2 != "valuewedontwant" 
select t 

フィールド、基準オペレータは

をデータベースに格納されている(そしてList<FieldCriteria>)および(上記に基づいて)このようないくつかのものになるだろうしています。

Email, Equals, "[email protected]" 
Email, Contains, "mydomain" Field1, 
Equals, "valuewewant" Field2, 
DoesNotEqual, "valuewedontwant" 

または

new FieldCriteria 
{ 
FieldName = "Email", 
Operator = 1, 
Value = "[email protected]" 
} 

だから私は持っている情報を使用して、私は条件の任意の数のクエリを作成できるようにしたいです。私はDynamic LinqとPredicateBuilderへの以前のリンクを見てきましたが、これを私自身の問題の解決策として視覚化することはできません。

何か提案がありがとうございます。

ダイナミックにLINQについての提案に続いて更新

、私は2つのフィールドと複数の条件で、シングル演算子を使用して、非常に基本的な解決策を考え出しました。現時点でLinqPadでコード化されているような少し原油ですが、結果はまさに私が望んでいたものです。

enum Operator 
{ 
    Equals = 1, 
} 

class Condition 
{ 
    public string Field { get; set; } 
    public Operator Operator { get; set;} 
    public string Value { get; set;} 
} 

void Main() 
{ 
    var conditions = new List<Condition>(); 

    conditions.Add(new Condition { 
     Field = "Email", 
     Operator = Operator.Equals, 
     Value = "[email protected]" 
    }); 

    conditions.Add(new Condition { 
     Field = "Email", 
     Operator = Operator.Equals, 
     Value = "[email protected]" 
    }); 

    conditions.Add(new Condition { 
     Field = "Field1", 
     Operator = Operator.Equals, 
     Value = "Chris" 
    }); 

    var statusConditions = "Status = 1"; 

    var emailConditions = from c in conditions where c.Field == "Email" select c; 
    var field1Conditions = from c in conditions where c.Field == "Field1" select c; 


    var emailConditionsFormatted = from c in emailConditions select string.Format("Email=\"{0}\"", c.Value); 
    var field1ConditionsFormatted = from c in field1Conditions select string.Format("Field1=\"{0}\"", c.Value); 

    string[] conditionsArray = emailConditionsFormatted.ToArray(); 
    var emailConditionsJoined = string.Join("||", conditionsArray); 
    Console.WriteLine(String.Format("Formatted Condition For Email: {0}",emailConditionsJoined)); 

    conditionsArray = field1ConditionsFormatted.ToArray(); 
    var field1ConditionsJoined = string.Join("||", conditionsArray); 
    Console.WriteLine(String.Format("Formatted Condition For Field1: {0}",field1ConditionsJoined)); 



    IQueryable results = ContactView.Where(statusConditions); 

    if (emailConditions != null) 
    { 
     results = results.Where(emailConditionsJoined); 
    } 

    if (field1Conditions != null) 
    { 
     results = results.Where(field1ConditionsJoined); 
    } 

    results = results.Select("id"); 

    foreach (int id in results) 
    { 
     Console.WriteLine(id.ToString()); 
    } 
} 

SQLを生成した場合。

-- Region Parameters 
DECLARE @p0 VarChar(1000) = 'Chris' 
DECLARE @p1 VarChar(1000) = '[email protected]' 
DECLARE @p2 VarChar(1000) = '[email protected]' 
DECLARE @p3 Int = 1 
-- EndRegion 
SELECT [t0].[id] 
FROM [Contacts].[ContactView] AS [t0] 
WHERE ([t0].[field1] = @p0) AND (([t0].[email] = @p1) OR ([t0].[email] = @p2)) AND ([t0].[status] = @p3) 

とコンソール出力:

Formatted Condition For Email: Email="[email protected]"||Email="[email protected]" 
Formatted Condition For Field1: Field1="Chris" 

はこれをクリーンアップし、他の演算子を追加必要とそれが格好良いです。

誰もがこれまでのところ、この上の任意のコメントを持っている場合は、任意の入力は、私は、動的LINQは選択肢の一つになると思い

答えて

1

をいただければ幸いです。 DLINQを使用すると、LINQクエリの一部を "string"として指定し、DLINQはその文字列をExpressionツリーにコンパイルして、基になるLINQプロバイダに渡すことができます。あなたの必要性も同じです。つまり、実行時に式ツリーを作成する必要があります。

OperatorFieldCriteriaに設定して、すべての必要な操作(等しい、少ない、それ以下など)を表すEnumとすることをお勧めします。次に、FieldCriteriaのリストを取得し、式ツリーを取得するためにDLINQに渡すことができる "式"文字列を返す関数を記述する必要があります。

+0

「LINQ to 」の考え方は、静的なC#コンパイル時の式を、実行のために基になるデータベースに送信する何らかの種類の文字列に変換することです。文字列をlinq式に変換して文字列に変換することをお勧めします:) –

+0

"静的"な表現はSQLに対して正しいですが、ユーザーが知りませんコンパイル時の式についてのことです。したがって、実行時に式を生成する必要があります。 DLINQは "文字列"からそれを行う1つの方法ですが、他の方法はExpression APIを使用して実行時に必要な式を作成することです。 – Ankur

9

LINQのトリックは、データからExpressionを構築することです。様々な動作構成するために使用することができる方法AndAlso注意(複数Whereと同じ、しかし単純な)、特に

var param = Expression.Parameter(typeof(MyObject), "t"); 

var body = Expression.Or(
      Expression.Equal(Expression.PropertyOrField(param, "Email"), Expression.Constant("[email protected]")), 
      Expression.Call(Expression.PropertyOrField(param, "Email"), "Contains", null, Expression.Constant("mydomain")) 
     ); 

body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "Field1"), Expression.Constant("valuewewant"))); 
body = Expression.AndAlso(body, Expression.NotEqual(Expression.PropertyOrField(param, "Field2"), Expression.Constant("valuewedontwant"))); 

var lambda = Expression.Lambda<Func<MyObject, bool>>(body, param); 

var data = source.Where(lambda); 

:一例として、図示した例を説明するために。

+0

上記のコードでは、fields/criteria /演算子を知る必要はありません。私のシナリオでは。コンパイル時には誰も知られておらず、その点で完全に動的である必要があります。ラムダ関数が私の現在の知識から少し外れていると私は誤解しています。 – ChrisBint

+0

@Chris noしかし、式 –

+0

を生成するコードを書く必要があります。どこでIN句を使用するのですか? – Neo

-2

これは、Linqによって簡単に実行できます。ここでは、追加の演算子をクエリオブジェクトに追加します。ここに例があります。

query = db.Contacts.Where(...); 
query = query.Where(...); 
query = query.Where(...); 

これはより簡単で短期間の解決方法です。

関連する問題