(这是我的问题的背景。)你可以跳到“问题”并阅读它,然后,如果你想直截了当地读到重点,你可能会回来浏览背景。对不起,这是一堵文字墙!)
我需要将一堆可怕的JSON存储在数据库中。本质上,有人获取了一个大型的XML文件,并通过简单地使用XML的XPath将其序列化为一个大的、扁平的JSON对象。下面是我的一个例子:
原始XML:
<statistics>
<sample>
<date>2012-5-10</date>
<duration>11.2</duration>
</sample>
<sample>
<date>2012-6-10</date>
<duration>13.1</duration>
</sample>
<sample>
<date>2012-7-10</date>
<duration>10.0</duration>
</sample>
</statistics>,我必须使用的可怕的JSON:(基本上只是上面的XPath )
{
"statistics":"",
"statistics/sample":"",
"statistics/sample/date":"2012-5-10",
"statistics/sample/duration":"11.2",
"statistics/sample@1":"",
"statistics/sample/date@1":"2012-6-10",
"statistics/sample/duration@1":"13.1",
"statistics/sample@2":"",
"statistics/sample/date@2":"2012-7-10",
"statistics/sample/duration@2":"10.0",
}现在,我需要将它放在一个包含statistics表的数据库中,该表包含date和duration列。
我现在是怎么做的:(或者至少是一个简单的例子)
Tuple<string, string>[] jsonToColumn = // maps JSON value to SQL table column
{
new Tuple<string, string>("statistics/sample/date", "date"),
new Tuple<string, string>("statistics/sample/duration", "duration")
};
// Parse the JSON text
// jsonText is just a string holding the raw JSON
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, object> json = serializer.DeserializeObject(jsonText) as Dictionary<string, object>;
// Duplicate JSON fields have some "@\d+" string appended to them, so we can
// find these and use them to help uniquely identify each individual sample.
List<string> sampleIndices = new List<string>();
foreach (string k in json.Keys)
{
Match m = Regex.Match(k, "^statistics/sample(@\\d*)?$");
if (m.Success)
{
sampleIndices .Add(m.Groups[1].Value);
}
}
// And now take each "index" (of the form "@\d+" (or "" for the first item))
// and generate a SQL query for its sample.
foreach (string index in compressionIndices)
{
List<string> values = new List<string>();
List<string> columns = new List<string>();
foreach (Tuple<string, string> t in jsonToColumn)
{
object result;
if (json.TryGetValue(t.Item1 + index, out result))
{
columns.Add(t.Item2);
values.Add(result);
}
}
string statement = "INSERT INTO statistics(" + string.Join(", ", columns) + ") VALUES(" + string.Join(", ", values) + ");";
// And execute the statement...
}但是,我想使用ADO.NET实体数据模型(或LINQ)而不是这种黑客行为,因为我需要在插入和应用某些更新之前开始执行一些查询,而创建和执行自己的SQL语句只是.太麻烦了。我创建了一个ADO.NET实体数据模型(.edmx)文件并进行了设置,现在我可以轻松地使用该模型与数据库进行交互和写入。
问题/问题
问题是,我不知道如何最好地将JSON映射到我的ADO.NET实体数据模型Statistic对象(它表示statistics表中的示例/记录)。最简单的方法是更改我的Tuple列表,使其使用指向成员的指针(如果这是C++,则为la Tuple<string, Statistic::*Duration>("statistics/sample/duration", &Statistic::Duration) ),但是( a )我甚至认为在C#中这是不可能的,而b)即使它使我的Tuple都有不同的类型。
我在这里有什么选择?如何最好地将JSON映射到我的Statistic对象?我对LINQ世界有点陌生,我想知道是否有一种方法(通过LINQ或其他什么)来映射这些值。
这是我所处的不太理想的位置(与如此糟糕的JSON一起工作),而且我认识到,考虑到我的情况,可能我目前的方法比任何其他方法都要好,如果是这样的话,我甚至会接受它作为我的答案。但是,我真的很想探索将这个JSON映射到一个C#对象(并最终映射到SQL数据库)的选项。
发布于 2012-08-31 00:58:40
如果整个问题是映射"JSON“,您必须使用POCO实体,下面是一个如何使用自定义JavascriptConverter反序列化它的示例
你的POCO实体:
public class Statistics
{
public Statistics()
{
Samples = new List<Sample>();
}
public List<Sample> Samples { get; set; }
}
public class Sample
{
public DateTime Date { get; set; }
public float Duration { get; set; }
}你的StatsConverter:
public class StatsConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
else if (type == typeof(Statistics))
{
Statistics statistics = null;
Sample sample = null;
{
foreach (var item in dictionary.Keys)
{
if (dictionary[item] is string && item.Contains("duration"))
sample.Duration = float.Parse(dictionary[item].ToString());
else if (dictionary[item] is string && item.Contains("date"))
sample.Date = DateTime.Parse((dictionary[item].ToString()));
else if (dictionary[item] is string && item.Contains("sample"))
{
sample = new Sample();
statistics.Samples.Add(sample);
}
else if (dictionary[item] is string && item.Contains("statistics"))
statistics = new Statistics();
}
}
return statistics;
}
return null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(Statistics)})); }
}
}现在是关于如何反序列化它的示例:
string json = @"{
""statistics"":"""",
""statistics/sample"":"""",
""statistics/sample/date"":""2012-5-10"",
""statistics/sample/duration"":""11.2"",
""statistics/sample@1"":"""",
""statistics/sample/date@1"":""2012-6-10"",
""statistics/sample/duration@1"":""13.1"",
""statistics/sample@2"":"""",
""statistics/sample/date@2"":""2012-7-10"",
""statistics/sample/duration@2"":""10.0""}";
//These are the only 4 lines you'll require on your code
JavaScriptSerializer serializer = new JavaScriptSerializer();
StatsConverter sc = new StatsConverter();
serializer.RegisterConverters(new JavaScriptConverter[] { new StatsConverter() });
Statistics stats = serializer.Deserialize<Statistics>(json);上面的stats对象将反序列化为包含3个Sample对象的Statistics对象的Samples集合。
发布于 2012-08-31 00:57:58
如果您使用ORM (例如EntityFramework),那么您只是在处理一个数据模型,所以假设您随后定义了一个模型类,比如.
public class Sample
{
public string Date { get; set; }
public double Duration { get; set; }
}然后你就可以做这样的事..。
List<Sample> samples = new List<Sample>();
Dictionary<string, object> data = ser.DeserializeObject(json) as Dictionary<string, object>;
var keys = data.Keys.ToList();
for (int i = 0; i <keys.Count; i++)
{
string k = keys[i];
if (Regex.IsMatch(k, "^statistics/sample(@\\d*)?$"))
{
samples.Add(new Sample
{
Date = (string)data[keys[i + 1]],
Duration = double.Parse((string)data[keys[i + 2]])
});
}
}我只是为这个例子填充了一个列表,如果您正在使用类似于EntityFramework的内容,那么您可以直接将实例添加到存储库/数据文本中。
https://stackoverflow.com/questions/12206777
复制相似问题