2012-04-24 10 views
4

私はソースからのデータを必要とするツールを書いています。このソースはユーザー指定であり、SQLバックエンド、独自のデータベース、フラットファイルシステムなど、ユーザーが知っているものである可能性があります。LINQ to Custom Query Language?

これらのタイプのクエリをフェッチするにはLinqを使用することをお勧めします。これはC#のように親しみやすく、多くの.NETコードを活用できます。

私はいくつかの調査を行っており、偉大なチュートリアルhereでIQueryProviderを構築することから始めました。それは私の道の大部分を得ていますが、ユーザーに式ツリーをカスタムコードに変換させる最善の方法については混乱しています。

私は式ツリーをカスタム "コード"(つまり "SQL")にする方法をユーザーが指定するための簡単なインターフェイスを提供する最良の方法を理解しようとしていますが、 - それはまさにそれだから、想像しています。

私の質問は、式ツリーをカスタム言語に変換する最良の方法は何ですか?

私は、私のカスタム構文解析ロジックを行うために 'Context'クラスを使用することができますが、私が使用するAPIはかなり低いレベルのようです - 単純に操作をマップするために、文字列に?

+0

これは間違いなく複雑で難しいです。私が知っている限り、それは現時点で必要なものです。これまでの場所を示すコードスニペットがありますか?どこがつまらないの? –

+0

何か不足しています。他の人にプロバイダを書くように依頼しているようです。式ツリーを提供していて、他の人がそれをSQLに変換してほしいと思っています。私は後方ですか? – Marc

+0

@justin私はいくつかのコードを一緒に掻き集めることができるかどうかを見ていきます。実際に送ったチュートリアルのリンクとはそれほど違いはありません。私はこれに対する正しいアプローチをもっと失いました。どのような質問にフィード: –

答えて

4

式ツリーをカスタムクエリ言語に変換する簡単で簡単な方法はありません。あなたは、LINQとDSLモデムの間で変換するためのビジターパターンを実装し

http://mehfuzh.github.com/LinqExtender/

てみLinqExtender与えたいと思うかもしれません。

LinqExtenderはカスタムLINQプロバイダを構築するためのツールキットです。 は、元のIQyeryableおよび IQueryProviderの実装より抽象化されたレイヤーを提供し、簡略化された構文ツリーを提供します。 さらに、投写、メソッド呼び出し、 による注文、メンバーの解析などを内部的にカバーしています。そのため、開発者は、彼の主なタスクマイナス複雑

に 多くを集中することができます。

1

一般に、ツリー構造を他の形式に変換する最も良い方法は、visitor patternを使用することです。

特に、msdnのExpressionVisitorクラスをチェックしてください。

0

私は訪問者パターンを調査しましたが、私が好きなように動作させることができなかったので、私はちょっと解決策をハッキングしました。 :/

私はベースサンプルを使ってツリーを解析し、文字列の集合を構築するベースのQueryContextを作成しました。私が終わったのは、このようなものでした。それは決して完全ではありませんが、それはまともなスタートだ:

public object Execute(Expression expression, bool IsEnumerable) 
    { 
     // Find the call to Where() and get the lambda expression predicate. 
     InnermostWhereFinder whereFinder = new InnermostWhereFinder(); 
     MethodCallExpression whereExpression = whereFinder.GetInnermostWhere(expression); 
     LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)(whereExpression.Arguments[1])).Operand; 

     // Send the lambda expression through the partial evaluator. 
     lambdaExpression = (LambdaExpression)Evaluator.PartialEval(lambdaExpression); 

     // Assemble the strings necessary to build this. 
     var strings = new List<string>(); 

     GetStrings(lambdaExpression.Body, strings); 

     var query = String.Join(" ", strings); 

     return ExecuteQuery(query); 
    } 

    public abstract object ExecuteQuery(string whereClause); 

    public abstract Dictionary<ExpressionType, string> ExpressionTypeToStringMap { get; } 

    public abstract string FormatFieldName(string fieldName); 
    public abstract string FormatConstant(string constant); 

    void GetStrings(System.Linq.Expressions.Expression expression, List<string> toReturn) 
    { 
     if (expression is BinaryExpression) 
     { 
      // Binary expression. Recurse and add to the list. 
      GetStrings((BinaryExpression)(expression), toReturn); 
     } 
     else if (expression is MemberExpression) 
     { 
      var e = (MemberExpression)(expression); 
      toReturn.Add(FormatFieldName(e.Member.Name)); 
     } 
     else if (expression is ConstantExpression) 
     { 
      var e = (ConstantExpression)(expression); 
      toReturn.Add(FormatConstant((string)(e.Value))); 
     } 
     else 
     { 
      throw new NotImplementedException("Unaware of how to handle type " + expression.GetType().ToString()); 
     } 
    } 

    string NodeTypeToString(ExpressionType type) 
    { 
     var map = ExpressionTypeToStringMap; 

     if(map.ContainsKey(type)) 
     { 
      return map[type]; 
     } 

     throw new NotImplementedException("Type '" + type.ToString() + "' not implemented in ExpressionTypeToStringMap."); 
    } 

    void GetStrings(BinaryExpression expression, List<string> toReturn) 
    { 
     toReturn.Add("("); 

     if (expression.Left != null) 
      GetStrings(expression.Left, toReturn); 

     toReturn.Add(NodeTypeToString(expression.NodeType)); 

     if (expression.Right != null) 
      GetStrings(expression.Right, toReturn); 

     toReturn.Add(")"); 
    } 

より良い実装が歓迎されているが、今のところ、少なくとも私がブロックされていないんです。