2017-11-20 4 views
0

誰かが重複としてマークしたが、そうではないのでこの質問を再掲載しています。可変内容のC#を使用してJsonをデシリアライズ

Webアプリケーションがデータを取得するためのAPIをC#で作成しています。私のWebアプリケーションでは、私は製品のリストを持つビューを持っています。今のところ、私はデータベースに格納されているすべての私の製品を返すルートを持っています。

ここで、Webアプリケーションが複合フィルタを作成する機能を追加したいと思います。 webappや、郵便配達員と一緒に、私のルートに到達することができるようにしたいと考えています(「let's say)/ api/product」には、webappが適用する必要があるすべてのフィルタを含む "filters"という名前のURlParamがあります。

私のWebAppに戻ってください(角度をつけてビルド)フィルタのツリーのように作成できるサービスがあります(下記のクラスアーキテクチャを参照してください)。 (そして、そう、このアーキテクチャを向上させることができる)

enter image description here

アイデアは、私はこのようなフィルタを構築することができるということです。私は自分の名前に「foo」を持っているすべての製品を取得したい場合や価格gretterと比べて15 $:

let filter = new AndNode(); 
filter.Add(new LikeNode("name", "foo")); 
filter.Add(new GTNode("price", 15)); 
filter.generateJson(); 

は、このJSONになります:

{ 
    "$and": [ 
     { 
      "$like": { "key": "name", "value": "foo" } 
     }, 
     { 
      "$gt": { "key": "price", "value": 15 } 
     } 
    ] 
} 

は今、このJSONは1つの要件を持っている:それは、複数のPRを含んでいてはいけませんオペラは一階です。これはSQLフィルタを生成するために使用されるため、jsonには最初のレベルに1つのノード、EQ、LIKE、GT、またはLTノードが含まれている必要があります。/ORノードは、次のレベルの各フィルタ間の論理「接続」を定義する。

だから、という意味があります:

{ 
    "$like": { "key": "name", "value": "foo" } 
} 

が有効であり、このSQL文につながる可能性:

SELECT * FROM products WHERE name LIKE "%foo%"; 

また:

{ 
    "$and": [ 
     { 
      "$like": { "key": "name", "value": "foo" } 
     }, 
     { 
      "$gt": { "key": "price", "value": 15 } 
     } 
    ] 
} 

は有効であり、このようつながる可能性SQLステートメント:

SELECT * FROM products WHERE name LIKE "%foo%" AND price > 15; 

しかし:

SELECT * FROM products WHERE name LIKE "%foo%" price > 15 

魔女が見つからないため、ANDやORキーワードで有効ではありません:それは、このSQL文を発生しますので、

{ 
    "$like": { "key": "name", "value": "foo" }, 
    "$eq": { "key": "price", "value": 5 }, 
} 

は有効ではありません。

私がしたいこと: 美しい世界では、このjsonをWebアプリケーションでシリアル化し、有効なURLパラメータ文字列に変換してAPI(c#)に送信したいと思います。 JSONをデシリアライズして、WebApp上で同じオブジェクト構造を取得します。 価格と名前の例では、LikeNodeクラスのインスタンスとGTNodeクラスのインスタンスの2つのオブジェクトを含むメンバー "child"を持つAndNodeクラスのインスタンスを持っています。

この実装は議論の余地があるかもしれませんが、今のところこれが必要です。今の

は、私が持っている:

public class EQNode 
{ 
    [JsonProperty("key")] 
    public string key { get; set; } 

    [JsonProperty("value")] 
    public int value { get; set; } 
} 

public class LikeNode 
{ 
    [JsonProperty("key")] 
    public string key { get; set; } 

    [JsonProperty("value")] 
    public string value { get; set; } 
} 

public class GTNode 
{ 
    [JsonProperty("key")] 
    public string key { get; set; } 

    [JsonProperty("value")] 
    public int value { get; set; } 
} 

public class LTNode 
{ 
    [JsonProperty("key")] 
    public string key { get; set; } 

    [JsonProperty("value")] 
    public int value { get; set; } 
} 

public class OrNode 
{ 
    [JsonProperty("$eq")] 
    public EQNode eq { get; set; } 
} 

public class AndNode 
{ 
    [JsonProperty("$eq")] 
    public EQNode eq { get; set; } 

    [JsonProperty("$like")] 
    public LikeNode like { get; set; } 

    [JsonProperty("$gt")] 
    public GTNode gt { get; set; } 

    [JsonProperty("$lt")] 
    public LTNode lt { get; set; } 

    [JsonProperty("$or")] 
    public List<OrNode> or { get; set; } 

    [JsonProperty("$and")] 
    public List<OrNode> and { get; set; } 
} 

public class RootObject 
{ 
    [JsonProperty("$and")] 
    public List<AndNode> and { get; set; } 

    [JsonProperty("$or")] 
    public List<OrNode> or { get; set; } 

    [JsonProperty("$eq")] 
    public EQNode eq { get; set; } 

    [JsonProperty("$like")] 
    public LikeNode like { get; set; } 

    [JsonProperty("$gt")] 
    public GTNode gt { get; set; } 

    [JsonProperty("$lt")] 
    public LTNode lt { get; set; } 
} 

これは、Visual Studioの「過去の特別な」機能によって生成された(と私は、JSON内の名前と一致するように、すべてのJsonPropertyデコレータを追加しました)。 それは動作しますが、これは私が期待したものではありません。

まず、WebApp構造から最も近い構造を継承したいと考えています。 第二に、私は、この生成されたコードが私のルートオブジェクトに$ eq、$ gt、$ lt、$ like、$ orまたは$ and nodeを持つことができるという事実を処理する方法が嫌い、そのようなきれいな構造を持っている方法はありません: (注:これは、これは単なるデモ用で、例えば、目的のために使用されるいくつかのデコレータが存在しない場合、またはひどく使用されている)

public class RootObject { 
    public FilterNode root; 
} 

public class FilterNode { 
} 

public class ConjunctionNode: FilterNode { 
    public FilterNode[] childs 
} 

[JsonObject("$and")] 
public class AndNode: ConjunctionNode { 
} 

[JsonObject("$or")] 
public class OrNode: ConjunctionNode { 
} 

[JsonObject("$like")] 
public class LikeNode: FilterNode { 
    public string key; 
    public string value; 
} 

[JsonObject("$eq")] 
public class EQNode: FilterNode { 
    public string key; 
    public string value; 
} 

[JsonObject("$gt")] 
public class GTNode: FilterNode { 
    public string key; 
    public string value; 
} 

[JsonObject("$lt")] 
public class LTNode: FilterNode { 
    public string key; 
    public string value; 
} 

だから、私たちが使用している場合サンプルJSON:私は使用することができ

{ 
    "$and": [ 
     { 
      "$like": { "key": "name", "value": "foo" } 
     }, 
     { 
      "$gt": { "key": "price", "value": 15 } 
     } 
    ] 
} 

RootObject obj = JsonConvert.DeserializeObject<RootObject>(filters); 

RootObjectの "root"メンバーをAndNodeのインスタンスとして使用します。 このAndNodeには、この子の配列にあるLikeNodeのインスタンスとGTNodeのインスタンスの2つのオブジェクトが含まれます。

これはできますか?

+0

最初の質問に回答がありますか? – Izzy

+0

私の元の投稿はそれほど詳細ではありませんでした。しかし、そこには次のような反応があります。「過去の特別な機能」を使うことは良いアドバイスであり、他の答えは私に詳細を求めていました。今のところ私はこれを解決するために答えました。 –

+0

新しい質問を投稿するのではなく、最初の質問を更新する必要があります。また、@ angsuman-rayは詳細なJSONを要求し、その外観からは戻っていません。 – Izzy

答えて

1

私はあなたの問題を詳しく調べました。逆直列化する傾向があるオブジェクトモデルに欠陥があります。また、キーが変更され続ける可能性があるので、直接デシリアライズを使用することはできません。だから、あなたはステップごとにjsonのステップを経て、それを辞書や任意のデータ型に検出して保存しなければならないでしょう。ここで

は、提案されたオブジェクトのクラスである:

using System.Collections.Generic; 

namespace ConsoleApp1 
{ 
    public class RootObject 
    { 
     public RootObject() 
     { 
      ConjunctionNode = new List<ConjunctionNode>(); 
     } 

     public List<ConjunctionNode> ConjunctionNode { get; set; } 
    } 

    public class FilterNode 
    { 
     public string Key { get; set; } 
     public string Value { get; set; } 
    } 

    public class ConjunctionNode 
    { 
     public LikeNode Like { get; set; } 
     public EQNode Eq { get; set; } 
     public GTNode Gt { get; set; } 
     public LTNode Lt { get; set; } 
    } 

    public class AndNode : ConjunctionNode 
    { 
    } 

    public class OrNode : ConjunctionNode 
    { 
    } 

    public class LikeNode : FilterNode 
    { 
    } 

    public class EQNode : FilterNode 
    { 
    } 

    public class GTNode : FilterNode 
    { 
    } 

    public class LTNode : FilterNode 
    { 
    } 
} 

は、オブジェクトが作られている方法を参照してください。今度は、jsonをステップバイステップで読み込み、分岐を作成して保存してから読み込んだり、読み込んだりして一緒に質問を作成する必要があります。

ここで私はデータを取得し始めました。このアプローチを使用すると一度試すことができます。あなたが困難に直面する場合、戻って来て自由に私はいくつかの作業を行うか、他の回避策を見つけることができます。

using Newtonsoft.Json; 
using System.IO; 

namespace ConsoleApp1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      RootObject rootObject = new RootObject(); 
      string json = @"{ ""$and"": [ { ""$like"": { ""key"": ""name"", ""value"": ""foo"" } }, {""$gt"": { ""key"": ""price"", ""value"": 15 } } ] } "; 
      //var rootObject = JsonConvert.DeserializeObject<RootObject>(json); 


      using (var reader = new JsonTextReader(new StringReader(json))) 
      { 
       while (reader.Read()) 
       { 
        //Console.WriteLine("{0} - {1} - {2}", reader.TokenType, reader.ValueType, reader.Value); 
        if (reader.TokenType.ToString() == "PropertyName") 
        { 
         //Console.WriteLine("Hi"); 
         CreateConjunctionNode(reader, rootObject); 
         //CreateFilterNode(reader, rootObject); 
         //Console.WriteLine(reader.Value); 
        } 
       } 
      } 
     } 

     private static void CreateFilterNode(JsonTextReader reader, RootObject rootObject) 
     { 
      if (reader.Value.ToString() == "$like") 
      { 
       LikeNode likeNode = new LikeNode(); 
      } 
      else if (reader.Value.ToString() == "$gt") 
      { 
       GTNode gTNode = new GTNode(); 
      } 
      else if (reader.Value.ToString() == "$lt") 
      { 
       LTNode lTNode = new LTNode(); 
      } 
      else if (reader.Value.ToString() == "$eq") 
      { 
       EQNode eQNode = new EQNode(); 
      } 
     } 

     private static void CreateConjunctionNode(JsonTextReader reader, RootObject rootObject) 
     { 
      if (reader.Value.ToString() == "$and") 
      { 
       rootObject.ConjunctionNode.Add(new AndNode()); 
      } 
      else if (reader.Value.ToString() == "$or") 
      { 
       rootObject.ConjunctionNode.Add(new OrNode()); 
      } 
     } 
    } 
} 
+0

こんにちは、あなたの答えをありがとう。私は "マニュアル"の逆直列化を避けようとしましたが、他の方法ではできないので、私はこれを実行します。これは、私のオブジェクトを必要なオブジェクト構造に逆直列化します。正確に私が必要とする最終結果。ありがとう! –

+0

常にゆるやかに物事を繋ぐようにしてください。モジュール化して再利用可能にする。 – inthevortex

関連する問題