将反序列化的JSON对象保存到有重复子实体的数据库中。

问题描述 投票:2回答:1

我正在从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();
        }
    }

谢谢期待。

c# json entity-framework ef-code-first
1个回答
2
投票

不幸的是,没有任何直接的方法来解决你的问题。

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 });
© www.soinside.com 2019 - 2024. All rights reserved.