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
相关产品推荐
相关产品推荐

