You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Function:移除多对多关联产生的JSON重复数据

解决多对多关联查询导致JSON重复数据的问题

兄弟,我太懂你这种多对多关联查出来一堆重复数据的痛苦了!本质原因是多表关联查询时,每一条关联的子记录(比如配料、条件)都会让主表的食谱数据重复一次——比如你的食谱有10个配料,数据库就会返回10条一模一样的食谱+不同配料的记录,转成JSON自然就会重复10次,而且配料/条件列表也会跟着重复输出。

给你几个实用的解决思路,结合你的代码场景来改:

思路1:分两次查询,内存中关联(最推荐)

先单独查询主表的食谱数据,再查询关联的配料和条件,最后把对应的子数据匹配到主记录上,完全避免数据库返回重复的主数据。

示例代码大概是这样:

List<JuiceIt> types = new List<JuiceIt>();
using (SqlConnection connection = new SqlConnection(CONNECTIONSTRING))
{
    connection.Open();
    
    // 第一步:查询所有不重复的食谱主数据
    string mainQuery = "SELECT Id, Name, Description FROM JuiceIt"; // 替换成你的主表实际字段
    using (SqlCommand mainComm = new SqlCommand(mainQuery, connection))
    {
        using (SqlDataReader reader = mainComm.ExecuteReader())
        {
            while (reader.Read())
            {
                types.Add(new JuiceIt
                {
                    Id = reader.GetInt32(0),
                    Name = reader.GetString(1),
                    Description = reader.GetString(2),
                    Ingredients = new List<Ingredient>(), // 初始化空列表
                    Conditions = new List<Condition>()
                });
            }
        }
    }
    
    // 第二步:查询所有配料,并匹配到对应的食谱
    string ingredientQuery = "SELECT JuiceItId, IngredientName, Quantity FROM Ingredients"; // 替换成你的配料表实际字段
    using (SqlCommand ingComm = new SqlCommand(ingredientQuery, connection))
    {
        using (SqlDataReader reader = ingComm.ExecuteReader())
        {
            while (reader.Read())
            {
                int juiceId = reader.GetInt32(0);
                var targetJuice = types.FirstOrDefault(j => j.Id == juiceId);
                if (targetJuice != null)
                {
                    targetJuice.Ingredients.Add(new Ingredient
                    {
                        Name = reader.GetString(1),
                        Quantity = reader.GetString(2)
                    });
                }
            }
        }
    }
    
    // 第三步:同理查询条件并匹配
    string conditionQuery = "SELECT JuiceItId, ConditionText FROM Conditions"; // 替换成你的条件表实际字段
    using (SqlCommand condComm = new SqlCommand(conditionQuery, connection))
    {
        using (SqlDataReader reader = condComm.ExecuteReader())
        {
            while (reader.Read())
            {
                int juiceId = reader.GetInt32(0);
                var targetJuice = types.FirstOrDefault(j => j.Id == juiceId);
                if (targetJuice != null)
                {
                    targetJuice.Conditions.Add(new Condition
                    {
                        Text = reader.GetString(1)
                    });
                }
            }
        }
    }
}

// 现在types里每个食谱只有一条,Ingredients和Conditions是完整的列表,转JSON就不会重复了

思路2:数据库端聚合子数据(适合简单场景)

如果你的子数据只需要字符串形式展示,可以用SQL的STRING_AGG(SQL Server 2017+支持)把多个配料/条件拼接成一个字符串,这样主表每条记录只返回一次。

示例SQL:

SELECT 
    j.Id, j.Name, j.Description,
    STRING_AGG(i.IngredientName + ' (' + i.Quantity + ')', ', ') AS Ingredients,
    STRING_AGG(c.ConditionText, ', ') AS Conditions
FROM JuiceIt j
LEFT JOIN Ingredients i ON j.Id = i.JuiceItId
LEFT JOIN Conditions c ON j.Id = c.JuiceItId
GROUP BY j.Id, j.Name, j.Description

这种方式不用改太多代码,但缺点是子数据只能是字符串,没法保留列表结构,如果需要JSON里是数组的话,还是思路1更合适。

额外提醒

如果你后续考虑用Entity Framework,记得用Include+ThenInclude的时候,要加上.Distinct()或者配置好导航属性的加载方式,避免重复数据,但你现在用的是原生SqlCommand,思路1是最直接有效的。

内容的提问来源于stack exchange,提问作者Ashley van Laer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:42:54