【问题标题】:How to read JSON data column in Entity Framework?如何读取实体框架中的 JSON 数据列?
【发布时间】:2020-08-13 19:04:56
【问题描述】:

我在 mysql 中创建了一个带有 JSON 列的数据库。 在 Swagger 中定义的 API。 将 JSON 写入数据库没有问题,但读取时,JSON 字段的值显示为转义字符串而不是 JSON

这是模型的一部分:

        /// <summary>
        /// Gets or Sets Doc
        /// </summary>
        [DataMember(Name="doc")]
        public Dictionary<string, string> Doc { get; set; }

我也尝试过使用字符串类型和 Dictionary 但不成功。

获取方法在这里:

public virtual IActionResult GetDataById([FromRoute][Required]int? dataId, [FromRoute][Required]string jsonNode)
    { 
       if(_context.Data.Any( a => a.Id == dataId)) {
          var dataSingle = _context.Data.SingleOrDefault( data => data.Id == dataId);
              return StatusCode(200, dataSingle);
            } else {
                return StatusCode(404);
            }
        }
}

生成的 JSON 响应看起来像这样:

{  
  "field1": "value1",
  "field2": "value2",
  "doc": "{\"key1\":\"value1\",\"key2\":\"value2\",\"key3\":{\"subkey3-1\":\"value3-1\",\"subkey3-2\":\"value3-2\"}}"
}

但正确的 JOSN 应该是这个:

{  
  "field1": "value1",
  "field2": "value2",
  "doc": {
       "key1":"value1",
       "key2":"value2",
       "key3":{
               "subkey3-1":"value3-1",
               "subkey3-2":"value3-2"
              }
          }
   }

如果我尝试只返回“Doc”(JSON) 字段,则响应 JSON 格式正确。

我尝试了不同的序列化/反序列化但不成功。

如果我有 public Dictionary Doc { get;放; } 在模型中出现错误:

fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HM1VN0F0I0IM", Request id "0HM1VN0F0I0IM:00000001": An unhandled exception was thrown by the application.
System.InvalidOperationException: The property 'Data.Doc' is of type 'Dictionary<string, string>' which is not supported by current database provider. Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'

and for public string Doc { get;放; } 在模型中我得到了“doc”字段值作为我上面提到的转义字符串。

最好的方法是什么?

【问题讨论】:

  • 据我所知,EF 不支持 JSON 列。应作为字符串放置并由 Json.NET 等 3rd 方库解析。
  • EF 自 2016 年起支持 JSON 类型。但现在这些都不起作用stackoverflow.com/questions/47455701/…
  • 你是对的。那只是数据类型的别名。需要由其他库解析。连接器库支持您链接的案例,而不是 EF 本身。

标签: c# entity-framework .net-core


【解决方案1】:

几天后我找到了解决办法。

如果您使用 Json.NET - Newtonsoft,您需要一个将字符串转换为对象的辅助方法,即 JObject。

public static JObject getJsonOutOfData (dynamic selectedData)
{
        var data = JsonConvert.SerializeObject(selectedData); 
        var jsonData = (JObject)JsonConvert.DeserializeObject<JObject>(data);

        if (selectedData.Doc != null) {
            JObject doc = JObject.Parse(selectedData.Doc);
            JObject docNode = JObject.Parse("{\"doc\":" + doc.ToString() + "}");
            var jsonDoc = (JObject)JsonConvert.DeserializeObject<JObject>(docNode.ToString());
            jsonData.Property("doc").Remove();

            jsonData.Merge(jsonDoc, new JsonMergeSettings 
            {
                MergeArrayHandling = MergeArrayHandling.Union
            });
        }
        return jsonData;
}

并在 IActionResult 方法中调用它

public virtual IActionResult GetDataById([FromRoute][Required]int? accidentId, [FromRoute][Required]string jsonNode)
{ 
    if (_context.Data.Any( a => a.Id == accidentId)) {

        var accidentSingle = _context.Data.SingleOrDefault( accident => accident.Id == accidentId);

        var result = getJsonOutOfData(accidentSingle); 

        return StatusCode(200, result.ToString());

    } else {

        return StatusCode(404);
    }
}

为了在 POST/PUT 请求中使用未转义的 JSON,您应该在数据库模型中将字符串类型作为 JSON 的属性类型,并创建一个额外的“请求”模型并将 JSON 属性设置为“对象”类型:

数据库模型:

[DataMember(Name="doc")]
public string Doc { get; set; }

请求模型:

[DataMember(Name="doc")]
public Object Doc { get; set; }

例如创建模型如下:

public virtual IActionResult CreateData([FromBody]DataCreateRequest body)
{          
    var accidentObject = new Data() {
        ColumnOne = body.ColumnOne,
        ColumnTwo = body.ColumnTwo,
        ColumnThree = body.ColumnThree,
        Doc = (bodyDoc != null) ? body.Doc.ToString() :  "{}"
        
    };

    _context.Data.Add(accidentObject);

    _context.SaveChanges();            
        
    return StatusCode(200, getJsonOutOfData(accidentObject));

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-01
    • 2023-03-08
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-14
    • 2011-08-28
    • 1970-01-01
    相关资源
    最近更新 更多