【问题标题】:Convert Dapper raw SQL Result to Nested JSON Array将 Dapper 原始 SQL 结果转换为嵌套 JSON 数组
【发布时间】:2021-08-02 21:42:41
【问题描述】:

我在 .Net Core 5 中开发了一个 web api,它使用 dapper 运行表值函数并返回 SQL 结果。然后将这些结果用于填充 VueJS 前端的各种选择框。然而,当我开始更多地构建前端时,我意识到我的 JSON 数组可以嵌套,以真正帮助减少我向服务器发出的请求数量,因为我的选择框是依赖的。例如,一个选择框包括州,然后下一个选择框与这些州的城市相关。通过在数据库中的状态表和城市表之间添加内部连接,可以轻松调整表值函数以返回单个表。加入键是一个名为 STATE_ID 的字段。因此,由于每个州有多个城市,我只有多行。所以现在我想弄清楚的是如何在我的 web api 和我的表值函数结果中获取这个结果而不使用模型到嵌套的 json 数组中,这样我的结果如下:

[{state: 'Maryland', cities :[{city: 'Baltimore'}, {city: 'Harford County'}]} , 
{state: 'Pennsylvania', cities :[{city: 'York'}, {city: 'Fawn Grove'}]}]

来自 A2Q00001_StateInfo(USERNUMBER) 的表值函数结果:

|      State_ID       |     State_Name   |      City_Name      |  
|---------------------|------------------|---------------------|
|          1          |      Maryland    |    Baltimore        |
|          1          |      Maryland    | Harford County      |
|          2          |  Pennsylvania    |    York             |
|          2          |  Pennsylvania    | Fawn Grove          |

我的控制器如下:

        public ActionResult StateAndCities([FromQuery] String USERNUMBER)
        {
 
            //We have parameters here just in case we want to use them
            IEnumerable queryResult;
            String query = "select * from dbo.A2Q00001_StateInfo(@USERNUMBER);";

            using (var connection = new SqlConnection(connectionString))
            {
                queryResult = connection.Query(query, new { USERNUMBER = USERNUMBER });
            }

            return Ok(queryResult);

        }

我在网上看到的所有教程都使用模型来创建嵌套的 JSON 对象并返回它,但是我不确定如何使用 asp.net 核心中 Ok() 函数中的序列化来创建嵌套对象。这甚至可能吗,还是我需要对 dapper 查询中的 queryResult 执行操作?朝着正确方向的任何一点都会很棒。

【问题讨论】:

    标签: json vue.js dapper asp.net-core-5.0


    【解决方案1】:

    我的建议:把它分成几个步骤。我猜你的A2Q00001_StateInfo UDF 在这里返回一个StateCity 列(编辑:我很接近,它是State_Name,通过编辑)等等。所以第一步:让我们读一下:

    class SomeType
    {
        public string State_Name { get; set; }
        public string City { get; set; }
    }
    //...
    var queryResult = connection.Query<SomeType>(
        "select State_Name, City from dbo.A2Q00001_StateInfo(@USERNUMBER);",
        new { USERNUMBER }).AsList();
    

    这会将我们的数据从数据库中获取到本地内存中。请注意,我过滤掉了不相关的列以减少开销。

    现在,下一步步骤是构建数据 - 看起来您想要按州聚合,并在每个州创建一个城市数组;所以:让我们这样做吧:

    var structured =
        from grp in queryResult.GroupBy(x => x.State_Name)
        select new
        {
            state = grp.Key,
            cities = grp.Select(row => new { city = row.City }).ToArray()
        };
    

    这为我们提供了一个投影(使用匿名类型)来进行我们想要的重组。最后,我们需要将其转换为 JSON;这可能很简单:

    return Ok(structured);
    

    或者您可能需要直接使用Json/JsonResult API。但是,既然数据是结构化的:任何 JSON 序列化程序都应该知道我们要在这里做什么。


    注意:您可能可以将所有这些重写为一个表达式,但是:不要这样做;你不是想给编译器留下深刻印象——不管怎样,它都不在乎。让代码清晰明了,便于下一个需要接触它的人(很可能是你)。

    【讨论】:

    • 我在原始问题中添加了上面的表格,以提供更好的上下文。通过将表移动到本地内存看起来类似于使用 Models 。如果是这种情况,是否可以不转移到本地内存并使用模型和使用我的原始表格结果?
    • @Bradyboyy88 无论哪种方式,您都必须将关系数据移动到本地内存,除非您想在数据库服务器上与FOR JSON 对抗,我不推荐。至于“使用模型”——嗯,是吗?这是很正常的,也是意料之中的——尽管可以说这是一个非常愚蠢的 DTO/POCO,所以称它为“模型”可能有点矫枉过正。我认为您更喜欢dynamic API?好吧,你可以用我上面写的所有东西来做到这一点,但我强烈建议不要这样做(并且为了上下文:我写了 Dapper)。您还可以使用值元组,即.Query&lt;(string State, string City)&gt;(....)
    • 感谢您的回复。所以我们有一个 SQL 人员在数据库服务器上为我们执行这些功能并获得我们想要的结果,这样我们就可以专注于其他事情并与我们的 web api 代码分开。您是否使用 LINQ 对 queryResult 对象进行了修改(我仍在学习 asp.net 核心,如果这是一个愚蠢的问题,请原谅我)?另外,如果要删除我端的任何 LINQ 要求并仅使用来自 db 服务器的结果,使用 For JSON 会有什么问题?
    • @Bradyboyy88 请记住,您的数据库服务器是您最有限的资源;还要记住 JSON 数据将是更大的带宽。如果您不关心这些事情,并且可以通过FOR JSON 弄清楚如何做到这一点:玩得开心。我不会用长杆碰它
    • 哈哈。我明白了。这是一个本地托管的数据库服务器和本地托管的 IIS 服务器,最多可能有 20 个用户。 FOR JSON 可能更容易实现,所以您是否介意在您的解决方案中显示您将如何从中创建结果,因为我现在已将表添加到问题中?此外,无论如何,我都会将您的解决方案标记为正确的解决方案,因为您的 LINQ 解决方案可能是最好的途径。非常感谢,因为您的解决方案非常清楚。
    猜你喜欢
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    • 1970-01-01
    相关资源
    最近更新 更多