2015-06-22 55 views
1

我有以下格式的JSON(从CouchDB的视图)反序列化JSON到C#类

{"rows":[ 
    {"key":["2015-04-01","524","http://www.sampleurl.com/"],"value":1}, 
    {"key":["2015-04-01","524","http://www.sampleurl2.com/"],"value":2}, 
    {"key":["2015-04-01","524","http://www.sampleurl3.com"],"value":1} 
]} 

我需要创建一个“服务”,从CouchDB中获取此数据并将其插入SQL服务器上(对于生成报告..)以有效的方式。我的第一个赌注是批量插入到SQL Server的这个json,像这样:Bulk Insert from Generic List into SQL Server with minimum lines of code

问题是,我该如何映射这个JSON到一个c#类?

Ultil现在这是我做过什么:

public class Row 
{ 
    public List<string> key { get; set; } 
    public int value { get; set; } 
} 

public class RootObject 
{ 
    public List<Row> rows { get; set; } 
} 

var example = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(jsontext); 

这给了我 “行” 的列表。每一行都有一个Key,每个键都是一个包含Date,Url和一个数字的数组。

我可以通过“行”循环并创建自己的对象,但这不会对我听起来非常高效。另外,JSON会很大,大概是5MB左右。

我需要的结构是这样的:

public class Click 
{ 
    public DateTime Date { get; set; } 
    public string Code { get; set; } 
    public string Url { get; set; } 
    public int Count { get; set; } 
} 

我如何可以提取的“钥匙”阵列,并将其映射到分离的特性。这样,我不需要for循环。

任何想法?

+0

有你进行一个简单的谷歌搜索实际上有吨的工作示例在您的浏览器中键入以下内容,例如 'C#stackoverflow反序列化JSON到C#类'让我们知道结果 – MethodMan

+0

我的问题不是反序列化。正如我在我的问题中解释过的,我已经这样做了。我的问题是以特定的方式绘制地图。 – jpgrassi

+0

如果您想要以特定方式生成类,您可以解释为什么它必须按特定顺序进行解释。一旦创建类并实例化对象,就可以访问所有公共属性..也许你需要更好地解释它 – MethodMan

回答

2

您可以为此创建一个自定义JsonConverter

[JsonConverter(typeof(ClickConverter))] 
public class Click 
{ 
    public DateTime Date { get; set; } 
    public string Code { get; set; } 
    public string Url { get; set; } 
    public int Count { get; set; } 
} 

public class ClickConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(Click).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var token = JToken.Load(reader); 
     if (token == null || token.Type == JTokenType.Null) 
      return null; 
     var click = (existingValue as Click ?? new Click()); 
     var key = token["key"] as JArray; 
     if (key != null && key.Count > 0) 
      click.Date = (DateTime)key[0]; 
     if (key != null && key.Count > 1) 
      click.Code = (string)key[1]; 
     if (key != null && key.Count > 2) 
      click.Url = (string)key[2]; 
     var value = token["value"]; 
     if (value != null) 
      click.Count = (int)value; 
     return click; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     // Fill in with the opposite of the code above, if needed 
     var click = value as Click; 
     if (click == null) 
      writer.WriteNull(); 
     else 
      serializer.Serialize(writer, 
       new 
       { 
        // Update the date string format as appropriate 
        // https://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx 
        key = new string[] { click.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), click.Code.ToString(CultureInfo.InvariantCulture), click.Url }, 
        value = click.Count 
       }); 
    } 
} 

public class RootObject 
{ 
    public List<Click> rows { get; set; } 
} 

已经直接应用转换器类,你可以(反)序列如常:

 var jsontext = @"{""rows"":[ 
    {""key"":[""2015-04-01"",""524"",""http://www.sampleurl.com/""],""value"":1}, 
    {""key"":[""2015-04-01"",""524"",""http://www.sampleurl2.com/""],""value"":2}, 
    {""key"":[""2015-04-01"",""524"",""http://www.sampleurl3.com""],""value"":1} 
]}"; 
     var rows = JsonConvert.DeserializeObject<RootObject>(jsontext); 
     Debug.WriteLine(JsonConvert.SerializeObject(rows, Formatting.Indented)); 
+0

这正是我想要的。非常感谢! – jpgrassi

2

给你。

public class Row 
{ 
    // Serialize/Deserialize the `key` into it's values. 
    public List<string> key { get { return new List<string>() { Date.ToString("yyyy-MM-dd"), Code, Url }; } set { Date = DateTime.Parse(value[0]); Code = value[1]; Url = value[2]; } } 
    // Serialize/Deserialize the `value` into `Count`. 
    public int value { get { return Count; } set { Count = value; } } 

    [ScriptIgnore] 
    public DateTime Date { get; set; } 
    [ScriptIgnore] 
    public string Code { get; set; } 
    [ScriptIgnore] 
    public string Url { get; set; } 
    [ScriptIgnore] 
    public int Count { get; set; } 

    public override string ToString() 
    { 
     return Date.ToString("yyyy-MM-dd") + ", " + Code + ", " + Url + ", " + Count; 
    } 
} 

public class RootObject 
{ 
    public List<Row> rows { get; set; } 
} 

public static void _Main(string[] args) 
{ 
    string json = "{\"rows\":[" + 
     "{\"key\":[\"2015-04-01\",\"524\",\"http://www.sampleurl.com/\"],\"value\":1}," + 
     "{\"key\":[\"2015-04-01\",\"524\",\"http://www.sampleurl2.com/\"],\"value\":2}," + 
     "{\"key\":[\"2015-04-01\",\"524\",\"http://www.sampleurl3.com\"],\"value\":1}" + 
     "]}"; 

    var jss = new JavaScriptSerializer(); 
    var example = jss.Deserialize<RootObject>(json); 

    foreach (Row r in example.rows) 
    { 
     Console.WriteLine(r.ToString()); 
    } 
} 

它应该是不言自明的。如果你想让我详细询问。尽管如此,要求的元素始终保持一致的顺序。

以上的输出:

2015-04-01, 524, http://www.sampleurl.com/, 1 
2015-04-01, 524, http://www.sampleurl2.com/, 2 
2015-04-01, 524, http://www.sampleurl3.com, 1 

这种方法的明显的好处是它具有低开销。这也很容易维护。这也意味着您可以明显地在其上具有ScriptIgnoreAttribute的属性上提供XmlIgnoreAttribute,并且它还会生成并读取有效的序列化XML。

注:我使用System.Web.Script.Serialization.JavaScriptSerializer。如果JSON.NET不使用ScriptIgnoreAttribute,那么您必须应用它使用的任何属性。 (我从来没有使用过JSON.NET。)

另一个注意:我写这个反对C#6.0.NET 4.6。你的结果可能有所不同