解析 JSON 数组以模拟 .NET Core 导致空集
Parse JSON array to model .NET Core causes empty set
通过调用 DbSet<T>.FromSqlRaw()
我可以在我的数据库中调用存储过程,returns 结果集如下:
Id VARCHAR(36)
FirstName VARCHAR(255)
LastName VARCHAR(255) NULL
Email VARCHAR(255) NULL
Numbers VARCHAR(?) NULL
Numbers
是一个 VARCHAR
字段,其中包含 JSON 个 SearchContactsNumber
数组:
public sealed class SearchContactsNumber
{
public Guid IdNumber { get; set; }
public string Type { get; set; }
public string Number { get; set; }
}
因此,例如,结果集可能是这样的:
"34f8d20f-21da-11eb-a249-de3268ec1e72" | "Paul" | "Newman" | "paul.newman@gmail.com" | "[{"IdNumber":"481d2957-21da-11eb-a249-de3268ec1e72","Type":"Telephone","Number":"+440001122333"},{...},{...}]"
调试 TestController.Index 端点:
public sealed class SearchContacts
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; set; }
}
public class TestController : Controller
{
private readonly DbContext _context;
public TestController(DbContext context)
{
_context = context;
}
public IActionResult Index()
{
var set = _context.SearchContacts.FromSqlRaw<SearchContacts>($"CALL `SearchContacts`()");
return Ok(set.ToList());
}
}
returns:
如何实现 json 字符串的完全绑定?
我在 ASP.NET Core 3.1 MVC 项目中使用 Pomelo.EntityFrameworkCore.MySql (3.2.3)
和 MySQL 8 数据库。
如果您将其设为 JsonObject,那么序列化将自动完成。 JsonObject 在系统命名空间下,Pomelo.EntityFrameworkCore.MySql 100%
支持它
查看下面的代码
using System;
public sealed class SearchContacts
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public JsonObject<SearchContactsNumber[]> Numbers { get; set; }
public SearchContactsNumber[] GetNumbers()
{
return Numbers.Object;
}
}
参见:How to use JsonObject of Pomelo.EntityFramework
您可以尝试这样的操作:
public sealed class SearchContacts
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; private set; }
private string NumbersJson { set => Numbers = JsonConvert.DeserializeObject<IEnumerable<SearchContactsNumber>>(value); }
}
只需确保将 Numbers 属性 映射到 NumbersJson
Pomelo 在几周前引入了 full-stack JSON 支持,最新的 Pomelo 版本中提供了该支持,并将在未来使用(以前的方法,如 JsonObject<T>
现在已弃用,不再在 5.0+ 中得到正式支持)。
要使用它,您需要添加以下软件包之一,具体取决于您想在后台使用哪个堆栈:
Pomelo.EntityFrameworkCore.MySql.Json.Microsoft
Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft
这些包支持 POCO 类、stack-specific DOM API 和简单的字符串映射。
我们还支持 top-level-only(非常快)到完全(较慢)的 JSON 实体更改跟踪(可以通过 [=15=14=] 参数控制) =] 和 UseNewtonsoftJson()
方法)。
这是一个完整的控制台示例项目,它演示了如何针对您的特定情况(此处使用 Microsoft 堆栈)使用 Pomelo 的 full-stack JSON 支持:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
namespace IssueConsoleTemplate
{
//
// EF Core Entities:
//
public sealed class SearchContact
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; set; }
}
//
// JSON Entities:
//
public sealed class SearchContactsNumber
{
public Guid IdNumber { get; set; }
public string Type { get; set; }
public string Number { get; set; }
}
//
// DbContext:
//
public class Context : DbContext
{
public DbSet<SearchContact> SearchContacts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseMySql(
"server=127.0.0.1;port=3306;user=root;password=;database=So64741089",
b => b.ServerVersion("8.0.21-mysql")
.CharSetBehavior(CharSetBehavior.NeverAppend)
.UseMicrosoftJson()) // <-- needed when using the Microsoft JSON stack (System.Text.Json)
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SearchContact>(
entity =>
{
entity.HasKey(e => e.IdContact);
entity.Property(e => e.Numbers)
.HasColumnType("json"); // <-- simple way to serialize any property from/to JSON
});
}
}
internal class Program
{
private static void Main()
{
using var context = new Context();
SetupDatabase(context);
var searchContacts = context.SearchContacts
.FromSqlInterpolated($"CALL `SearchContacts`()")
.ToList();
Debug.Assert(searchContacts.Count == 1);
Debug.Assert(searchContacts[0].Numbers.Count() == 1);
Debug.Assert(searchContacts[0].Numbers.First().IdNumber == new Guid("481d2957-21da-11eb-a249-de3268ec1e72"));
}
private static void SetupDatabase(Context context)
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var connection = context.Database.GetDbConnection();
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = @"CREATE PROCEDURE `SearchContacts`()
BEGIN
SELECT '34f8d20f-21da-11eb-a249-de3268ec1e72' as `IdContact`,
'Paul' as `FirstName`,
'[{""IdNumber"":""481d2957-21da-11eb-a249-de3268ec1e72"",""Type"":""Telephone"",""Number"":""+440001122333""}]' as `Numbers`;
END";
command.ExecuteNonQuery();
}
}
}
通过调用 DbSet<T>.FromSqlRaw()
我可以在我的数据库中调用存储过程,returns 结果集如下:
Id VARCHAR(36)
FirstName VARCHAR(255)
LastName VARCHAR(255) NULL
Email VARCHAR(255) NULL
Numbers VARCHAR(?) NULL
Numbers
是一个 VARCHAR
字段,其中包含 JSON 个 SearchContactsNumber
数组:
public sealed class SearchContactsNumber
{
public Guid IdNumber { get; set; }
public string Type { get; set; }
public string Number { get; set; }
}
因此,例如,结果集可能是这样的:
"34f8d20f-21da-11eb-a249-de3268ec1e72" | "Paul" | "Newman" | "paul.newman@gmail.com" | "[{"IdNumber":"481d2957-21da-11eb-a249-de3268ec1e72","Type":"Telephone","Number":"+440001122333"},{...},{...}]"
调试 TestController.Index 端点:
public sealed class SearchContacts
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; set; }
}
public class TestController : Controller
{
private readonly DbContext _context;
public TestController(DbContext context)
{
_context = context;
}
public IActionResult Index()
{
var set = _context.SearchContacts.FromSqlRaw<SearchContacts>($"CALL `SearchContacts`()");
return Ok(set.ToList());
}
}
returns:
如何实现 json 字符串的完全绑定?
我在 ASP.NET Core 3.1 MVC 项目中使用 Pomelo.EntityFrameworkCore.MySql (3.2.3)
和 MySQL 8 数据库。
如果您将其设为 JsonObject,那么序列化将自动完成。 JsonObject 在系统命名空间下,Pomelo.EntityFrameworkCore.MySql 100%
支持它查看下面的代码
using System;
public sealed class SearchContacts
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public JsonObject<SearchContactsNumber[]> Numbers { get; set; }
public SearchContactsNumber[] GetNumbers()
{
return Numbers.Object;
}
}
参见:How to use JsonObject of Pomelo.EntityFramework
您可以尝试这样的操作:
public sealed class SearchContacts
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; private set; }
private string NumbersJson { set => Numbers = JsonConvert.DeserializeObject<IEnumerable<SearchContactsNumber>>(value); }
}
只需确保将 Numbers 属性 映射到 NumbersJson
Pomelo 在几周前引入了 full-stack JSON 支持,最新的 Pomelo 版本中提供了该支持,并将在未来使用(以前的方法,如 JsonObject<T>
现在已弃用,不再在 5.0+ 中得到正式支持)。
要使用它,您需要添加以下软件包之一,具体取决于您想在后台使用哪个堆栈:
Pomelo.EntityFrameworkCore.MySql.Json.Microsoft
Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft
这些包支持 POCO 类、stack-specific DOM API 和简单的字符串映射。
我们还支持 top-level-only(非常快)到完全(较慢)的 JSON 实体更改跟踪(可以通过 [=15=14=] 参数控制) =] 和 UseNewtonsoftJson()
方法)。
这是一个完整的控制台示例项目,它演示了如何针对您的特定情况(此处使用 Microsoft 堆栈)使用 Pomelo 的 full-stack JSON 支持:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
namespace IssueConsoleTemplate
{
//
// EF Core Entities:
//
public sealed class SearchContact
{
public Guid IdContact { get; set; }
public string FirstName { get; set; }
public IEnumerable<SearchContactsNumber> Numbers { get; set; }
}
//
// JSON Entities:
//
public sealed class SearchContactsNumber
{
public Guid IdNumber { get; set; }
public string Type { get; set; }
public string Number { get; set; }
}
//
// DbContext:
//
public class Context : DbContext
{
public DbSet<SearchContact> SearchContacts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseMySql(
"server=127.0.0.1;port=3306;user=root;password=;database=So64741089",
b => b.ServerVersion("8.0.21-mysql")
.CharSetBehavior(CharSetBehavior.NeverAppend)
.UseMicrosoftJson()) // <-- needed when using the Microsoft JSON stack (System.Text.Json)
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SearchContact>(
entity =>
{
entity.HasKey(e => e.IdContact);
entity.Property(e => e.Numbers)
.HasColumnType("json"); // <-- simple way to serialize any property from/to JSON
});
}
}
internal class Program
{
private static void Main()
{
using var context = new Context();
SetupDatabase(context);
var searchContacts = context.SearchContacts
.FromSqlInterpolated($"CALL `SearchContacts`()")
.ToList();
Debug.Assert(searchContacts.Count == 1);
Debug.Assert(searchContacts[0].Numbers.Count() == 1);
Debug.Assert(searchContacts[0].Numbers.First().IdNumber == new Guid("481d2957-21da-11eb-a249-de3268ec1e72"));
}
private static void SetupDatabase(Context context)
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var connection = context.Database.GetDbConnection();
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = @"CREATE PROCEDURE `SearchContacts`()
BEGIN
SELECT '34f8d20f-21da-11eb-a249-de3268ec1e72' as `IdContact`,
'Paul' as `FirstName`,
'[{""IdNumber"":""481d2957-21da-11eb-a249-de3268ec1e72"",""Type"":""Telephone"",""Number"":""+440001122333""}]' as `Numbers`;
END";
command.ExecuteNonQuery();
}
}
}