0

通过调用DbSet<T>.FromSqlRaw(),我可以调用数据库中的存储过程,它返回如下结果集:

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());
    }
}

返回:

在此处输入图像描述

如何归档 json 字符串的完整绑定?

Pomelo.EntityFrameworkCore.MySql (3.2.3)在 ASP.NET Core 3.1 MVC 项目中使用 MySQL 8 数据库。

4

3 回答 3

7

Pomelo 几周前引入了全栈 JSON 支持,在最新的 Pomelo 版本中可用,并将继续使用(以前的方法,如JsonObject<T>现在已弃用,5.0+ 不再正式支持)。

要使用它,您需要添加以下软件包之一,具体取决于您要在后台使用哪个堆栈:

  • Pomelo.EntityFrameworkCore.MySql.Json.Microsoft
  • Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft

这些包支持 POCO 类、特定于堆栈的 DOM API 和简单的字符串映射。

我们还支持从仅顶级(非常快)到完整(较慢)对 JSON 实体的更改跟踪(可以通过and方法的options参数进行控制)。UseMicrosoftJson()UseNewtonsoftJson()

这是一个完全工作的控制台示例项目,它演示了如何针对您的特定情况使用 Pomelo 的全栈 JSON 支持(这里使用 Microsoft 堆栈):

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();
        }
    }
}
于 2020-11-08T20:21:02.583 回答
2

如果将其设为 JsonObject,则序列化将自动完成。JsonObject 位于 System 命名空间下,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;
    }
}

参见:如何使用 Pomelo.EntityFramework 的 JsonObject

于 2020-11-08T19:03:47.567 回答
0

你可以尝试这样的事情:

    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

于 2020-11-08T19:11:22.627 回答