动态生成JSON写入Avro文件后Snowflake出现转义字符问题
问题与解决方案
问题背景
向Avro文件写入数据(将同步至Snowflake),其中一个字段为动态结构的JSON——JSON结构仅在运行时确定,无法提前创建对应实体类序列化生成。目前用StringBuilder手动拼接JSON,同步到Snowflake后出现转义反斜杠,尝试Replace(@"\", string.Empty)无效。
相关代码与现象:
- Field类定义:
public class Field { public string Name { get; set; } public string Value { get; set; } }
- 手动拼接JSON的代码:
StringBuilder newJson = new StringBuilder(); newJson.Append("{"); foreach (Field requestedField in fields) { newJson.Append($"\"{requestedField.Name}\": {FormatValue(requestedField.Value)}"); if (requestedField != fields.Last()) newJson.Append(", "); } newJson.Append("}");
- 期望生成的JSON:
{ "ProductName": "Bucket", "Price": 199, "OrderCode": "G1234", "Deleted": true }
- 实际Snowflake中出现转义的JSON:
{ \"ProductName\": \"Bucket\", \"Price\": 199, \"OrderCode\": \"G1234\", \"Deleted\": true }
核心原因
Avro序列化时会将string类型字段的特殊字符(如双引号)自动转义。你手动拼接的JSON被当作普通字符串处理,Avro会给双引号添加转义反斜杠,最终导致Snowflake中呈现带转义的内容。
解决方案
方案1:用动态Avro Record存储JSON结构(推荐)
直接基于运行时字段构建Avro的GenericRecord,让Avro以结构化方式存储数据,Snowflake读取时会自动解析为JSON对象,彻底避免转义问题。
代码示例:
using Avro; using Avro.Generic; using System.Collections.Generic; // 1. 动态生成Avro Record Schema List<Field> avroFields = new List<Field>(); foreach (var field in fields) { Schema fieldSchema = field.Type.ToLower() switch { "bit" => BooleanSchema.Instance, "int" => Int32Schema.Instance, "bigint" => Int64Schema.Instance, "decimal" => DoubleSchema.Instance, "varchar" => StringSchema.Instance, _ => StringSchema.Instance }; avroFields.Add(new Field(field.Name, fieldSchema)); } RecordSchema dynamicSchema = RecordSchema.Create("DynamicRecord", avroFields); // 2. 构建GenericRecord GenericRecord dynamicRecord = new GenericRecord(dynamicSchema); foreach (var field in fields) { dynamicRecord[field.Name] = field.Type.ToLower() switch { "bit" => bool.Parse(field.Value), "int" => int.Parse(field.Value), "bigint" => long.Parse(field.Value), "decimal" => double.Parse(field.Value), _ => field.Value }; } // 3. 将dynamicRecord作为目标字段的值写入Avro文件 // 替换原有Avro写入逻辑,将此record赋值给对应字段即可
方案2:用JSON库生成字符串,以字节数组写入Avro
若必须用字符串类型存储JSON,可将JSON转为字节数组写入Avro的bytes类型字段,避免Avro转义,再在Snowflake侧解析。
代码示例:
using Newtonsoft.Json.Linq; using System.Text; // 1. 用JObject构建正确的JSON结构 JObject jsonObj = new JObject(); foreach (var field in fields) { jsonObj[field.Name] = field.Type.ToLower() switch { "bit" => bool.Parse(field.Value), "int" => int.Parse(field.Value), "decimal" => decimal.Parse(field.Value), _ => field.Value }; } string jsonStr = jsonObj.ToString(Newtonsoft.Json.Formatting.None); // 2. 转为字节数组写入Avro的bytes字段 byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonStr); // 3. 将jsonBytes作为目标字段的值写入Avro文件
Snowflake读取时解析:
SELECT PARSE_JSON(TO_VARCHAR(json_bytes_field)) AS json_field FROM your_table;
内容的提问来源于stack exchange,提问作者Calid Xavier
相关产品推荐
相关产品推荐

