我正在从API调用中检索一些JSON,并将其反序列化为它的组件对象。 一切都很顺利,直到我把它保存到数据库中。 原因是,有一些子对象有重复的键(就数据而言是绝对正确的),但当我保存顶层对象时,它在子对象上抛出了一个主键违规的错误。
下面是我的JSON样本(我知道它不完整)。
{
"count": 149,
"filters": {},
"competitions": [
{
"id": 2006,
"area": {
"id": 2001,
"name": "Africa",
"countryCode": "AFR",
"ensignUrl": null
},
"name": "WC Qualification",
"code": null,
"emblemUrl": null,
"plan": "TIER_FOUR",
"currentSeason": {
"id": 555,
"startDate": "2019-09-04",
"endDate": "2021-11-16",
"currentMatchday": null,
"winner": null
},
"numberOfAvailableSeasons": 2,
"lastUpdated": "2018-06-04T23:54:04Z"
},
{
"id": 2025,
"area": {
"id": 2011,
"name": "Argentina",
"countryCode": "ARG",
"ensignUrl": null
},
"name": "Supercopa Argentina",
"code": null,
"emblemUrl": null,
"plan": "TIER_FOUR",
"currentSeason": {
"id": 430,
"startDate": "2019-04-04",
"endDate": "2019-04-04",
"currentMatchday": null,
"winner": null
},
"numberOfAvailableSeasons": 2,
"lastUpdated": "2019-05-03T05:08:18Z"
},
{
"id": 2023,
"area": {
"id": 2011,
"name": "Argentina",
"countryCode": "ARG",
"ensignUrl": null
},
"name": "Primera B Nacional",
"code": null,
"emblemUrl": null,
"plan": "TIER_FOUR",
"currentSeason": {
"id": 547,
"startDate": "2019-08-16",
"endDate": "2020-06-14",
"currentMatchday": 30,
"winner": null
},
"numberOfAvailableSeasons": 3,
"lastUpdated": "2020-05-15T00:00:02Z"
},
目前我只是保存顶层对象,我希望所有的子对象也能保存。 如果我关闭了子对象的主键(使它们成为身份列而不是它们的实际值),这一切都能正常工作,所有的子对象都能完美保存。 正如你从JSON中看到的,"区域 "2011是一个重复的,有两个比赛有相同的区域,所以数据方面是正确的,但是在打开 "区域 "的适当的主键时,它跳闸了,因为它试图插入一个重复的记录。
因此,我完全理解这是怎么回事,为什么它会出错,我想知道的是,有没有一个简单的方法,只是告诉EF忽略重复键错误。 我不能在保存顶层对象时添加try catch,因为当它遇到错误时,它只是什么也不保存。
我试过保存各个子对象,在保存之前测试它们是否存在,但是当它试图保存父级对象时,它也试图保存子对象,让我遇到同样的问题。
这是我保存顶层对象的代码(为简单起见删减了)。
public class Area
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int id { get; set; }
public string name { get; set; }
public string countryCode { get; set; }
public string ensignUrl { get; set; }
}
public class Winner
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int id { get; set; }
public string name { get; set; }
public string shortName { get; set; }
public string tla { get; set; }
public string crestUrl { get; set; }
}
public class CurrentSeason
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int id { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public int? currentMatchday { get; set; }
public Winner winner { get; set; }
}
public class Competition
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int id { get; set; }
public Area area { get; set; }
public string name { get; set; }
public string code { get; set; }
public string emblemUrl { get; set; }
public string plan { get; set; }
public CurrentSeason currentSeason { get; set; }
public int numberOfAvailableSeasons { get; set; }
public DateTime lastUpdated { get; set; }
}
public class Example
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int count { get; set; }
public IList<Competition> competitions { get; set; }
}
static void Main(string[] args)
{
string json = GET(@"http://my.url.com/api/stuff");
Example example = JsonConvert.DeserializeObject<Example>(json);
using(var db = new ExampleContext())
{
db.Examples.Add(example);
db.SaveChanges();
}
}
谢谢期待。
不幸的是,没有任何直接的方法来解决你的问题。
EF Change Tracker
追踪实体的引用,解决你的问题的唯一方法是为所有相同的实体创建相同的对象。areas
.
为此,你有两个选择。
1- 绕过 example
此行之后
Example example = JsonConvert.DeserializeObject<Example>(json);
并找出所有相同的 areas
并将其全部替换为其中之一。
2-使用 保存参考文献处理 NewtonSoft的功能。但它需要应用在Serialize和Deserialize两端。
服务器(Api)端:
string json = JsonConvert.SerializeObject(data, Formatting.Indented,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
客户端:
var example = JsonConvert.DeserializeObject<Example>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });