2015-08-20 2 views
1

Допустим, у меня есть некоторые данные, как показано ниже:Строительство JSON из табличной иерархических данных

{ 
    "Menu": { 
     "aaa": "aaa", 
     "bbb": { 
      "ccc": "ccc", 
      "ddd": "ddd" 
     }, 
     "eee": "eee" 
    } 
} 

Я могу сохранить этот тип иерархических данных в базе данных в реляционной образом подобное:

http://i.stack.imgur.com/lmuq1.jpg 
список

Пример:

List<MenuItem> menuItems = new List<MenuItem>(); 
    menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 }); 
    menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 }); 
    menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 }); 
    menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 }); 
    menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 }); 
    menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 }); 

так что, когда я получаю реляционные данные из БД в список из MenuItem объектов, как я могу транслировать его обратно в json?

public partial class MenuItem 
{ 
    public int SiteMenuId { get; set; } 
    public int SiteId { get; set; } 
    public string MenuName { get; set; } 
    public string Url { get; set; } 
    public Nullable<int> ParentId { get; set; } 
    public int CreatedUser { get; set; } 
    public System.DateTime CreatedDate { get; set; } 
    public Nullable<int> ModifiedUser { get; set; } 
    public Nullable<System.DateTime> ModifiedDate { get; set; } 
} 

Должен ли я использовать словарь или ExpandoObject или что-то еще? Я хочу иметь тот же формат, что и в начале.

+1

Посмотрите newtonsoft - http://www.newtonsoft.com/json и как сериализовать json. – Will

+0

Спасибо, что я знаю о newtonsoft. Но я хочу, чтобы мой json был таким же, как и первый формат. Именно об этом я и спрашиваю. – anilca

+0

Обычно я использую Automapper для преобразования между моделью, отображаемой через http и dto. – Will

ответ

1

с помощью Json.net, мы можем написать собственный конвертер для создания желаемых из списка JSON из MenuItem.

ПРИМЕЧАНИЕ. Я пропустил часть считывателя для конвертера, чтобы сделать ее кратким (поскольку она не связана с вопросом), но логика будет похожа на часть записи.

class MenuItemJsonConverter : JsonConverter 
{ 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof (MenuItemCollection) || objectType==typeof(List<MenuItem>); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var map=new Dictionary<int,JObject>(); 
     var collection = (List<MenuItem>) value; 
     var root=new JObject(); 

     var nestedItems=collection.GroupBy(i => i.ParentId).ToLookup(g=>g.Key); //or we can simply check for item.Url==null but I believe this approach is more flexible 

     foreach (var item in collection) 
     { 
      if (item.ParentId == null) 
      { 
       var firstObj=new JObject(); 
       root.Add(item.MenuName,firstObj); 
       map.Add(item.SiteMenuId,firstObj); 
       continue; 
      } 

      var parent = map[item.ParentId.Value]; 

      if (!nestedItems.Contains(item.SiteMenuId)) 
      { 
       parent.Add(item.MenuName,item.Url); 
       continue; 
      } 

      var jObj = new JObject(); 
      parent.Add(item.MenuName, jObj); 
      map.Add(item.SiteMenuId, jObj); 
     } 

     writer.WriteRaw(root.ToString()); 
    } 
} 

здесь прямой пример использования:

 var menuItems = new List<MenuItem>(); 
     menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 }); 

     var json = JsonConvert.SerializeObject(menuItems,Formatting.Indented,new MenuItemJsonConverter()); 

или мы можем извлечь из List<> и украсить его [JsonConverter(typeof(MenuItemJsonConverter))] для большего удобства:

[JsonConverter(typeof(MenuItemJsonConverter))] 
class MenuItemCollection : List<MenuItem> 
{  
} 

затем просто использовать его как:

 var menuItems = new MenuItemCollection(); 
     menuItems.Add(new MenuItem() { SiteMenuId = 1, ParentId = null, MenuName = "Menu", Url = null, SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 2, ParentId = 1, MenuName = "aaa", Url = "aaa", SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 3, ParentId = 1, MenuName = "bbb", Url = null, SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 4, ParentId = 3, MenuName = "ccc", Url = "ccc", SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 5, ParentId = 3, MenuName = "ddd", Url = "ddd", SiteId = 1 }); 
     menuItems.Add(new MenuItem() { SiteMenuId = 6, ParentId = 1, MenuName = "eee", Url = "eee", SiteId = 1 }); 

     var json = JsonConvert.SerializeObject(menuItems,Formatting.Indented); 
0

Если вы можете использовать NewtonSoft, используйте десериализацию содержимого JSON и посмотрите, как выглядит результирующий объект. Затем создайте класс, который соответствует результирующей структуре десериализации. Обратное проектирование ...

Используйте этот метод:

var obj = JsonConvert.DeserializeObject("{ "menu": { "aaa": "aaa"......} }"); 

Позвольте мне знать ваши выводы.

+0

Но мой json не будет таким же каждый раз. Подумайте о количестве предметов в json и глубине их будет – anilca

1

Вы можете создать KeyValuePair объект для этой цели:

KeyValuePair<string, List<Object>> toExport = new KeyValuePair<int, int>("Menu", new List<Object>()); 

Затем, вы можете добавить элементы, например:

toExport.Value.Add(new KeyValuePair<string, string>("aaa", "aaa")); 

Чтобы добавить составные вещи к этому, вы можете сделать что-то подобное :

KeyValuePair<string, List<Object>> bbb = new KeyValuePair<string, List<Object>>("bbb", new List<Object>()); 
bbb.Value.Add(new KeyValuePair<string, string>("ccc", "ccc")); 
bbb.Value.Add(new KeyValuePair<string, string>("ddd", "ddd")); 
toExport.Value.Add(bbb); 

Когда вы построили свой объект, вы можете использоватьNewtonSoftспособ.

Вы также можете создать вспомогательный класс, который поможет вам.

EDIT: Создание динамических данных.

public class DynamicKeyValueBuilder { 

    private KeyValuePair<string, List<Object>> toExport; 

    public DynamicKeyValueBuilder(string mainKey) { 
     toExport = new KeyValuePair<string, List<Object>>(mainKey, new List<Object>()); 
    } 

    public string getJSON() { 
     return JsonConvert.SerializeObject(this.toExport); 
    } 

    private KeyValuePair<string, List<Object>> searchParent(List<string> path) { 
     KeyValuePair<string, List<Object>> temp = (KeyValuePair<string, List<Object>>)this.toExport; 
     int index = 0; 
     while (index < path.Count) { 
      try { 
       temp = (KeyValuePair<string, List<Object>>)temp.First(item => item.Key == path.ElementAt(index)); //throws exception if value is not list or the element was not found 
       index++; 
      } catch (Exception exception) { 
       //handle exceptions 
       return null; 
      } 
     } 
     return temp; 
    } 

    //If value == null, we create a list 
    public boolean addElement(List<string> path, string key, string value) { 
     KeyValuePair<string, Object> parent = this.searchParent(path); 
     //failure 
     if (parent == null) { 
      return false; 
     } 
     parent.Value.Add((value == null) ? (new KeyValuePair<string, List<Object>>(key, new List<Object>())) : (new KeyValuePair<string, string>(key, value))); 
     return true; 
    } 

} 

код не тестировался, если у вас возникнут ошибки, пожалуйста, дайте мне знать, а не только вниз голосования, я считаю, я помещаю усилия здесь, чтобы помочь.

Вы можете создать экземпляр этого класса, как это:

DynamicKeyValueBuilder myBuilder = new DynamicKeyValueBuilder("Menu"); 

Когда вы собираетесь добавить новый <string, string> элемент, вы можете сделать это следующим образом:

myBuilder.Add(new List<string>(new string[] {"Menu"}), "aaa", "aaa"); 

Когда вы собираетесь добавить новый <string, List<Object>> элемент, вы можете сделать это следующим образом:

myBuilder.Add(new List<string>(new string[] {"Menu"}), "bbb", null); 

Когда y НУ намерено добавить что-то внутри внутренний список, вы можете сделать это следующим образом:

myBuilder.Add(new List<string>(new string[] {"Menu", "bbb"}), "ccc", "ccc"); 
+0

Спасибо, кажется, что объекты KeyValuePair мне помогут. Но мой главный вопрос: как я могу построить соответствующий объект с помощью динамических данных. Подумайте о количестве предметов в json и их глубине. – anilca

+0

Я редактирую свой ответ, чтобы дать вам больше информации. Горе со мной ... –

+0

@anilca, я отредактировал свой ответ. Код непроверен, дайте мне знать, если вы найдете в нем проблемы. –

Смежные вопросы