C# 将JSON对象/字符串数组解析为新的自定义类

C# 将JSON对象/字符串数组解析为新的自定义类,c#,json,entity-framework,json.net,entity-framework-core,C#,Json,Entity Framework,Json.net,Entity Framework Core,我试图解析一些JSON数据,并最终将其存储在数据库中 我在存储字符串/值集合时遇到问题,这些字符串/值本身不是对象 例如,“callingCodes”和“Alt拼写” 我想将它们存储在一个SQL表中,该表将引用它们所属的国家 这是JSON的一个示例: { "name":"Puerto Rico", "topLevelDomain":[ ".pr" ], "alpha2Code":"PR", "alpha3Code":"PRI", "callingC

我试图解析一些JSON数据,并最终将其存储在数据库中

我在存储字符串/值集合时遇到问题,这些字符串/值本身不是对象

例如,“callingCodes”和“Alt拼写”

我想将它们存储在一个SQL表中,该表将引用它们所属的国家

这是JSON的一个示例:

{
   "name":"Puerto Rico",
   "topLevelDomain":[
      ".pr"
   ],
   "alpha2Code":"PR",
   "alpha3Code":"PRI",
   "callingCodes":[
      "1787",
      "1939"
   ],
   "capital":"San Juan",
   "altSpellings":[
      "PR",
      "Commonwealth of Puerto Rico",
      "Estado Libre Asociado de Puerto Rico"
   ],
   "region":"Americas",
   "subregion":"Caribbean",
   "population":3474182,
   "latlng":[
      18.25,
      -66.5
   ]
},
我最初创建了一些C#类,以使用

我将这些值存储为字符串列表,我做到了:

 public List<string> CallingCodes { get; set; }
因此,我将父对象更改为:

public ICollection<CallingCode> CallingCodes { get; set; }
public ICollection调用代码{get;set;}
是否可以将字符串值定向到新类的“Code”属性中

还是我想把两条逻辑硬塞进一条


为JSON创建模型并手动将其重新构造为我的新DB/实体框架模型的正确方法是什么?

这是您自动生成的类:

    public class RootObject
    {
        public string name { get; set; }
        public List<string> topLevelDomain { get; set; }
        public string alpha2Code { get; set; }
        public string alpha3Code { get; set; }
        public List<string> callingCodes { get; set; }
        public string capital { get; set; }
        public List<string> altSpellings { get; set; }
        public string region { get; set; }
        public string subregion { get; set; }
        public int population { get; set; }
        public List<double> latlng { get; set; }
    }
当然
MyRootObject
只是一个例子

是为JSON创建模型的正确方法,并且手动 将这些重新构造为我的新DB/实体框架模型

有些人可能会在他们的代码中使用它,有些人甚至会做得更糟。但是,我个人喜欢将模型/DTO用于我可能了解的数据

我是不是想把两条逻辑硬塞进一条

对。但是,这要视情况而定。每次都可以强类型/定义对象和all,也可以仅键入Ser/Deser

您的数据是已知的(没有未知属性或任何东西,为什么每次都要序列化和反序列化它?

解决方案1:如果按原样使用JSON创建DB条目

public class Country //assuming this is country data
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Alpha2Code { get; set; }

    public string Alpha3Code { get; set; }

    public string Capital { get; set; }

    public string Region { get; set; }

    public string Subregion { get; set; }

    public long Population { get; set; }

    public string TopLevelDomains { get; set; }

    public string CallingCodes { get; set;}

    public string AltSpellings { get; set; }

    public double Longitude { get; set;}

    public double Latitude { get; set; }
}
实体

public class Country //assuming this is country data
{
    public int Id { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("alpha2Code")]
    public string Alpha2Code { get; set; }

    [JsonProperty("alpha3Code")]
    public string Alpha3Code { get; set; }

    [JsonProperty("capital")]
    public string Capital { get; set; }

    [JsonProperty("region")]
    public string Region { get; set; }

    [JsonProperty("subregion")]
    public string Subregion { get; set; }

    [JsonProperty("population")]
    public long Population { get; set; }

    [JsonProperty("topLevelDomain")]
    public virtual List<TopLevelDomain> TopLevelDomains { get; set; }

    [JsonProperty("callingCodes")]
    public virtual List<CallingCodes> CallingCodes { get; set; }

    [JsonProperty("altSpellings")]
    public virtual List<AltSpellings> AltSpellings { get; set; }

    [JsonProperty("latlng")]
    public virtual List<Coordinates> Coordinates { get; set; }
}

public class TopLevelDomain
{
    public int Id { get; set; }

    [ForeignKey("Country")]
    public int CountryId {get; set; }

    public virtual Country Country { get; set; }

    public string DomainName { get; set; }
}

public class CallingCodes
{
    public int Id { get; set; }

    [ForeignKey("Country")]
    public int CountryId {get; set; }

    public virtual Country Country { get; set; }

    public string Code { get; set;} // either store it as String
    //OR
    public long Code { get; set;}
}

public class AltSpellings
{
    public int Id { get; set; }

    [ForeignKey("Country")]
    public int CountryId {get; set; }

    public virtual Country Country { get; set; }

    public string AltSpelling { get; set; }
}

public class Coordinates
{
    public int Id { get; set; }

    [ForeignKey("Country")]
    public int CountryId {get; set; }

    public virtual Country Country { get; set; }

    public double Coordinates { get; set; } //again either as string or double, your wish. I would use double
}
型号

public class CountryJson 
{
    public int Id { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("alpha2Code")]
    public string Alpha2Code { get; set; }

    [JsonProperty("alpha3Code")]
    public string Alpha3Code { get; set; }

    [JsonProperty("capital")]
    public string Capital { get; set; }

    [JsonProperty("region")]
    public string Region { get; set; }

    [JsonProperty("subregion")]
    public string Subregion { get; set; }

    [JsonProperty("population")]
    public long Population { get; set; }

    [JsonProperty("topLevelDomain")]
    public List<string> TopLevelDomains { get; set; }

    [JsonProperty("callingCodes")]
    public List<string> CallingCodes { get; set;}

    [JsonProperty("altSpellings")]
    public List<string> AltSpellings { get; set; }

    [JsonProperty("latlng")]
    public List<string> Latlng { get; set; }
}
public类
{
公共int Id{get;set;}
[JsonProperty(“名称”)]
公共字符串名称{get;set;}
[JsonProperty(“alpha2Code”)]
公共字符串Alpha2Code{get;set;}
[JsonProperty(“alpha3Code”)]
公共字符串Alpha3Code{get;set;}
[JsonProperty(“资本”)]
公共字符串大写字母{get;set;}
[JsonProperty(“区域”)]
公共字符串区域{get;set;}
[JsonProperty(“次区域”)]
公共字符串子区域{get;set;}
[JsonProperty(“人口”)]
公共长填充{get;set;}
[JsonProperty(“topLevelDomain”)]
公共列表TopLevelDomains{get;set;}
[JsonProperty(“调用代码”)]
公共列表调用代码{get;set;}
[JsonProperty(“altSpellings”)]
公共列表替换拼写{get;set;}
[JsonProperty(“latlng”)]
公共列表Latlng{get;set;}
}
像这样使用它

//assuming using Newtonsoft

var myJson = ....assuming one Country;
var myJsonList = ...assuming List<Country>;

var country = JsonConvert.DeserializeObject<Country>(myJson);
var countries = JsonConvert.DeserializeObject<List<Country>>(myJson);
//assuming using Newtonsoft

var myJson = ....assuming one Country;

var countryJson = JsonConvert.DeserializeObject<CountryJson>(myJson);
//Write a Mapper Or Manual Map like below
var countryEntity = new Country 
{
    Name = countryJson.Name,
    ...
    TopLevelDomains = JsonConvert.Serialize(countryJson.TopLevelDomains),
    CallingCodes = JsonConvert.Serialize(countryJson.CallingCodes),
    ...//same for all list (NOTE: YOU NEED TO DESERIALIZE IT WHEN YOU FETCH IT FROM DB
    Longitude = countryJson.Latlng.ElementAt(0),//assuming 0 is longi, 1 is lat
    Latitude = countryJson.Latlng.ElementAt(1)//you can do it like above as well as string if you want
}
//假设使用Newtonsoft
var myJson=…假设一个国家;
var countryJson=JsonConvert.DeserializeObject(myJson);
//编写一个映射器或手动映射,如下所示
var countryEntity=新国家/地区
{
Name=countryJson.Name,
...
TopLevelDomains=JsonConvert.Serialize(countryJson.TopLevelDomains),
CallingCodes=JsonConvert.Serialize(countryJson.CallingCodes),
…//对所有列表都一样(注意:从DB获取时需要对其进行反序列化)
经度=countryJson.Latlng.ElementAt(0),//假设0是longi,1是lat
Latitude=countryJson.Latlng.ElementAt(1)//您可以像上面一样操作,如果需要,还可以使用string
}

这是从这样的JSON中自动生成的类。这里的难点是基本类型的列表

public class RootObject
{
    public string name { get; set; }
    public List<string> topLevelDomain { get; set; }
    public string alpha2Code { get; set; }
    public string alpha3Code { get; set; }
    public List<string> callingCodes { get; set; }
    public string capital { get; set; }
    public List<string> altSpellings { get; set; }
    public string region { get; set; }
    public string subregion { get; set; }
    public int population { get; set; }
    public List<double> latlng { get; set; }
}
公共类根对象
{
公共字符串名称{get;set;}
公共列表topLevelDomain{get;set;}
公共字符串alpha2Code{get;set;}
公共字符串alpha3Code{get;set;}
公共列表调用代码{get;set;}
公共字符串大写字母{get;set;}
公共列表替换拼写{get;set;}
公共字符串区域{get;set;}
公共字符串子区域{get;set;}
公共整数填充{get;set;}
公共列表latlng{get;set;}
}
某些数据库(如PostgreSQL)支持将数组作为基元类型。如果您使用PostgreSQL,则可以将这些属性设置为基元类型的数组,并按原样存储在服务器上

对于不支持数组的其他数据库,您不能将基元值列表存储到数据库的单个列中。处理它的最简单方法是引入序列化并创建可存储到服务器的单个字符串。因此,查看上面的类,对于
public list topLevelDomain
属性,您可以在中重写它这样,

[NotMapped]
public List<string> topLevelDomain
{
    get => Deserialize(TopLevelDomainString);
    set => TopLevelDomainString = Serialize(value);
}
public string TopLevelDomainString { get; set; }
[未映射]
公共列表topLevelDomain
{
get=>反序列化(TopLevelDomainString);
set=>TopLevelDomainString=序列化(值);
}
公共字符串TopLevelDomainString{get;set;}
使用
NotMapped
属性,EF将不会映射
topLevelDomain
属性。但是
TopLevelDomainString
将被持久化到数据库,它将从
topLevelDomain
获取值。至于
序列化/反序列化
方法,您可以使用任何序列化方法。您可以使用
JsonSerializer
直接(因为您已经在使用JSON对象。或者您可以使用
作为分隔符组合字符串,并使用它从服务器拆分字符串


从EF Core 2.1版本开始,您可以直接使用该特性来提供funcs进行转换(本质上类似于上面的序列化代码)to EF和EF将在从/向服务器读取/保存数据时执行此操作。这将避免您必须创建其他CLR属性。

为什么不为列表属性创建新实体?EF Core不支持直接收集基元类型。特别是类中未导航的每个属性都映射到数据库中的一列。不可能将字符串数组以其形式存储到任何关系数据库。将来当EF Core支持文档数据库时,您可以将JSON直接映射到该数据库。如果您想存储在da之上
//assuming using Newtonsoft

var myJson = ....assuming one Country;

var countryJson = JsonConvert.DeserializeObject<CountryJson>(myJson);
//Write a Mapper Or Manual Map like below
var countryEntity = new Country 
{
    Name = countryJson.Name,
    ...
    TopLevelDomains = JsonConvert.Serialize(countryJson.TopLevelDomains),
    CallingCodes = JsonConvert.Serialize(countryJson.CallingCodes),
    ...//same for all list (NOTE: YOU NEED TO DESERIALIZE IT WHEN YOU FETCH IT FROM DB
    Longitude = countryJson.Latlng.ElementAt(0),//assuming 0 is longi, 1 is lat
    Latitude = countryJson.Latlng.ElementAt(1)//you can do it like above as well as string if you want
}
public class RootObject
{
    public string name { get; set; }
    public List<string> topLevelDomain { get; set; }
    public string alpha2Code { get; set; }
    public string alpha3Code { get; set; }
    public List<string> callingCodes { get; set; }
    public string capital { get; set; }
    public List<string> altSpellings { get; set; }
    public string region { get; set; }
    public string subregion { get; set; }
    public int population { get; set; }
    public List<double> latlng { get; set; }
}
[NotMapped]
public List<string> topLevelDomain
{
    get => Deserialize(TopLevelDomainString);
    set => TopLevelDomainString = Serialize(value);
}
public string TopLevelDomainString { get; set; }