You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

452 lines
20 KiB

// <auto-generated/>
// ReSharper disable All
// Disable StyleCop analysis for this file
// <copyright file="TransformerService.cs" company="Manus">
// Copyright (c) Manus. All rights reserved.
// </copyright>
3 days ago
using medical.transfomer.dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
3 days ago
namespace medical.insu.transfomer
{
/// <summary>
/// JSON配置转换服务类
/// </summary>
public class TransformerService
{
private readonly TransformationConfig _config;
private readonly IValueConverter _valueConverter; // 用于字典转换等
/// <summary>
/// 构造函数
/// </summary>
/// <param name="configuration">转换配置</param>
/// <param name="valueConverter">值转换器实例 (可选)</param>
public TransformerService(TransformationConfig configuration, IValueConverter valueConverter = null)
{
_config = configuration ?? throw new ArgumentNullException(nameof(configuration));
_valueConverter = valueConverter ?? new DefaultValueConverter(); // 提供一个默认实现
}
/// <summary>
/// 从JSON字符串加载配置
/// </summary>
/// <param name="jsonConfig">包含配置的JSON字符串</param>
/// <returns>TransformationConfig 实例</returns>
public static TransformationConfig LoadConfigFromJson(string jsonConfig)
{
if (string.IsNullOrWhiteSpace(jsonConfig))
{
throw new ArgumentException("JSON configuration string cannot be null or empty.", nameof(jsonConfig));
}
try
{
return JsonSerializer.Deserialize<TransformationConfig>(jsonConfig, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true // 允许属性名不区分大小写
});
}
catch (JsonException ex)
{
// 在实际应用中,这里应该记录更详细的错误日志
throw new InvalidOperationException("Failed to deserialize JSON configuration.", ex);
}
}
/// <summary>
/// 将源数据对象根据指定方法转换为目标JSON字符串 (系统对象 -> 接口JSON)
/// </summary>
/// <param name="methodName">方法名称 (来自 method_config)</param>
/// <param name="sourceObject">源数据对象 (通常是一个C#对象或字典)</param>
/// <returns>转换后的JSON字符串</returns>
public string Transform(string methodName, object sourceObject)
{
// 1. 查找方法配置
var method = _config.MethodConfigs.FirstOrDefault(m => m.METHOD_NAME == methodName);
if (method == null)
{
throw new ArgumentException($"Method '{methodName}' not found in configuration.", nameof(methodName));
}
// 2. 筛选出适用于当前方法和出参的组装规则 (parametr_type = 2 代表出参)
var assemblyRules = _config.ObjectAssemblies
.Where(a => a.METHOD_REF == method.METHOD_ID && a.PARAMETR_TYPE == 2 && a.ASSEMBLY_TYPE == "interface") // 假设是系统到接口的转换
.OrderBy(a => a.OBJECT_PATH) // 排序以确保父节点先创建
.ToList();
if (!assemblyRules.Any())
{
// 如果没有找到针对出参的interface类型组装规则,可能需要抛出错误或返回空JSON
// 根据实际需求,这里也可以查找 'sys' 类型的规则,取决于转换方向的定义
Console.WriteLine($"Warning: No 'interface' assembly rules found for method '{methodName}' and parameter type 2 (output).");
return "{}"; // 或者抛出异常
}
var rootNode = new JsonObject(); // 创建JSON根节点
// 3. 遍历组装规则,构建JSON
foreach (var rule in assemblyRules)
{
// 3.1 查找对应的映射规则 (通过MappingTable关联到ObjectMapping的ObjectTableName或MappingId)
// 假设 MappingTable 直接对应 ObjectMapping 中的 ObjectTableName
var mapping = _config.ObjectMappings.FirstOrDefault(om => om.OBJECT_TABLE_NAME == rule.MAPPING_TABLE && om.INTERFACE_FIELD != null);
// 如果MappingTable也可能是MappingId, 则需要调整查找逻辑
// var mapping = _config.ObjectMappings.FirstOrDefault(om =>
// (om.ObjectTableName == rule.MappingTable || om.MappingId == rule.MappingTable) &&
// om.InterfaceField != null);
if (mapping == null)
{
Console.WriteLine($"Warning: No object mapping found for MappingTable '{rule.MAPPING_TABLE}' in assembly rule '{rule.ID}'. Skipping path '{rule.OBJECT_PATH}'.");
continue;
}
// 3.2 从源对象获取值
// 这里简化处理,假设sourceObject是字典或可以通过反射获取属性
// 实际应用中需要更健壮的取值逻辑
object sourceValue = GetValueFromSourceObject(sourceObject, mapping.SYSTEM_FIELD);
if (sourceValue == null && rule.OBJECT_PATH.Contains("patientId")) // 示例:特定字段的空值处理
{
// Console.WriteLine($"Debug: Source value for {mapping.SystemField} is null.");
}
// 3.3 值转换 (字典翻译、类型转换等)
object convertedValue = _valueConverter.Convert(
sourceValue,
mapping.SYSTEM_FIELD_TYPE?.ToString(), // Convert decimal? to string
mapping.OBJECT_FIELD_TYPE?.ToString(), // Convert decimal? to string
mapping.SYSTEM_DICT_NAME,
mapping.OBJECT_DICT_NAME,
rule.PARAMETR_TYPE
);
// 3.4 根据ObjectPath设置值到JSON节点
SetValueByJsonPath(rootNode, rule.OBJECT_PATH, convertedValue, rule.OBJECT_TYPE);
}
return rootNode.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
}
/// <summary>
/// 从源对象中获取指定属性的值 (简化实现)
/// </summary>
private object GetValueFromSourceObject(object source, string propertyName)
{
if (source == null || string.IsNullOrEmpty(propertyName)) return null;
if (source is IDictionary<string, object> dictSource)
{
return dictSource.TryGetValue(propertyName, out var val) ? val : null;
}
if (source is JsonElement jsonElementSource && jsonElementSource.ValueKind == JsonValueKind.Object)
{
return jsonElementSource.TryGetProperty(propertyName, out var prop) ? GetValueFromJsonElement(prop) : null;
}
// 尝试通过反射获取属性值
var propInfo = source.GetType().GetProperty(propertyName);
if (propInfo != null)
{
return propInfo.GetValue(source);
}
// 如果是JsonNode,尝试获取
if (source is JsonNode jnSource)
{
var parts = propertyName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
JsonNode currentNode = jnSource;
foreach (var part in parts)
{
if (currentNode is JsonObject jo && jo.ContainsKey(part))
{
currentNode = jo[part];
}
else
{
return null; // 路径不存在
}
}
if (currentNode is JsonValue jv) return jv.GetValue<object>();
return currentNode; //可能是JsonObject或JsonArray
}
Console.WriteLine($"Warning: Property '{propertyName}' not found in source object of type '{source.GetType().Name}'.");
return null;
}
private object GetValueFromJsonElement(JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.String: return element.GetString();
case JsonValueKind.Number:
if (element.TryGetInt32(out int i)) return i;
if (element.TryGetInt64(out long l)) return l;
if (element.TryGetDouble(out double d)) return d;
return element.GetDecimal(); // Fallback
case JsonValueKind.True: return true;
case JsonValueKind.False: return false;
case JsonValueKind.Null: return null;
case JsonValueKind.Object: return element; // Or parse to dictionary
case JsonValueKind.Array: return element; // Or parse to list
default: return null;
}
}
/// <summary>
/// 根据JSONPath在JsonNode中设置值 (简化实现, 支持基本的路径)
/// </summary>
private void SetValueByJsonPath(JsonNode rootNode, string path, object value, int objectType)
{
if (string.IsNullOrWhiteSpace(path) || rootNode == null) return;
// 移除起始的 "$."
if (path.StartsWith("$."))
{
path = path.Substring(2);
}
var segments = path.Split('.');
JsonNode currentNode = rootNode;
for (int i = 0; i < segments.Length - 1; i++)
{
var segment = segments[i];
if (currentNode[segment] == null)
{
// 根据下一个segment是否是数组索引来决定创建JsonObject还是JsonArray
// 此处简化:如果下一个路径是数字,则认为是数组索引,但设计文档中object_type更可靠
// 暂时简单处理,都创建JsonObject,实际应根据object_assembly的object_type判断
currentNode[segment] = new JsonObject();
}
currentNode = currentNode[segment];
if (currentNode == null) // 防御性编程,如果中间节点创建失败或路径无效
{
Console.WriteLine($"Error: Could not navigate or create path segment '{segment}' in JSON path '{path}'.");
return;
}
}
var lastSegment = segments.Last();
JsonNode valueNode = value == null ? null : JsonValue.Create(value); // JsonValue.Create可以处理多种基本类型
if (value is JsonElement je)
{
valueNode = JsonNode.Parse(je.GetRawText());
}
else if (value is IDictionary<string, object> dictValue)
{
valueNode = new JsonObject();
foreach(var kvp in dictValue)
{
((JsonObject)valueNode).Add(kvp.Key, JsonValue.Create(kvp.Value));
}
}
else if (value is IEnumerable<object> listValue && !(value is string)) // 确保不是字符串
{
var jsonArray = new JsonArray();
foreach (var item in listValue)
{
jsonArray.Add(JsonValue.Create(item));
}
valueNode = jsonArray;
}
if (objectType == 2) // 列表类型
{
if (currentNode[lastSegment] == null || !(currentNode[lastSegment] is JsonArray))
{
currentNode[lastSegment] = new JsonArray();
}
((JsonArray)currentNode[lastSegment]).Add(valueNode);
}
else // 对象类型
{
((JsonObject)currentNode)[lastSegment] = valueNode;
}
}
/// <summary>
/// 将接口JSON字符串根据指定方法转换为目标系统对象 (接口JSON -> 系统对象)
/// </summary>
/// <typeparam name="T">期望的目标系统对象类型</typeparam>
/// <param name="methodName">方法名称 (来自 method_config)</param>
/// <param name="sourceJson">源JSON字符串</param>
/// <returns>转换后的目标系统对象</returns>
public T Transform<T>(string methodName, string sourceJson) where T : new()
{
// 1. 查找方法配置
var method = _config.MethodConfigs.FirstOrDefault(m => m.METHOD_NAME == methodName);
if (method == null)
{
throw new ArgumentException($"Method '{methodName}' not found in configuration.", nameof(methodName));
}
// 2. 解析源JSON
JsonNode sourceNode;
try
{
sourceNode = JsonNode.Parse(sourceJson);
}
catch (JsonException ex)
{
throw new ArgumentException("Invalid source JSON string.", nameof(sourceJson), ex);
}
if (sourceNode == null) throw new ArgumentException("Parsed source JSON is null.", nameof(sourceJson));
// 3. 筛选出适用于当前方法和入参的组装规则 (parametr_type = 1 代表入参)
var assemblyRules = _config.ObjectAssemblies
.Where(a => a.METHOD_REF == method.METHOD_ID && a.PARAMETR_TYPE == 1 && a.ASSEMBLY_TYPE == "sys") // 假设是接口到系统的转换
.OrderBy(a => a.OBJECT_PATH)
.ToList();
if (!assemblyRules.Any())
{
Console.WriteLine($"Warning: No 'sys' assembly rules found for method '{methodName}' and parameter type 1 (input).");
return new T(); // 或者抛出异常
}
T targetObject = new T();
// 4. 遍历组装规则, 填充目标对象
foreach (var rule in assemblyRules)
{
var mapping = _config.ObjectMappings.FirstOrDefault(om => om.OBJECT_TABLE_NAME == rule.MAPPING_TABLE && om.SYSTEM_FIELD != null);
if (mapping == null)
{
Console.WriteLine($"Warning: No object mapping found for MappingTable '{rule.MAPPING_TABLE}' in assembly rule '{rule.ID}'. Skipping path '{rule.OBJECT_PATH}'.");
continue;
}
// 4.1 从源JSON获取值
object sourceValue = GetValueByJsonPath(sourceNode, rule.OBJECT_PATH);
// 4.2 值转换
object convertedValue = _valueConverter.Convert(sourceValue, mapping.OBJECT_FIELD_TYPE, mapping.SYSTEM_FIELD_TYPE, mapping.OBJECT_DICT_NAME, mapping.SYSTEM_DICT_NAME, rule.PARAMETR_TYPE);
// 4.3 设置到目标对象属性 (简化实现, 假设属性名与SystemField一致)
// 实际应用中可能需要更复杂的属性设置逻辑,例如处理嵌套对象
var propInfo = typeof(T).GetProperty(mapping.SYSTEM_FIELD);
if (propInfo != null && propInfo.CanWrite)
{
try
{
// 类型转换,确保赋的值与属性类型匹配
var typedValue = ConvertToPropertyType(convertedValue, propInfo.PropertyType);
propInfo.SetValue(targetObject, typedValue);
}
catch (Exception ex)
{
Console.WriteLine($"Error setting property '{mapping.SYSTEM_FIELD}': {ex.Message}");
}
}
else
{
Console.WriteLine($"Warning: Property '{mapping.SYSTEM_FIELD}' not found or not writable on type '{typeof(T).Name}'.");
}
}
return targetObject;
}
/// <summary>
/// 根据JSONPath从JsonNode中获取值 (简化实现)
/// </summary>
private object GetValueByJsonPath(JsonNode rootNode, string path)
{
if (string.IsNullOrWhiteSpace(path) || rootNode == null) return null;
if (path.StartsWith("$.")) path = path.Substring(2);
var segments = path.Split('.');
JsonNode currentNode = rootNode;
foreach (var segment in segments)
{
if (currentNode is JsonObject jo && jo.ContainsKey(segment))
{
currentNode = jo[segment];
}
// TODO: Add support for array indexing if needed, e.g., "items[0].name"
else
{
return null; // 路径不存在
}
}
if (currentNode is JsonValue jv) return jv.GetValue<object>(); // GetValue<object> 会尝试转换为合适的.NET类型
return currentNode; //可能是JsonObject或JsonArray,调用者需要进一步处理
}
/// <summary>
/// 将值转换为目标属性类型 (简化实现)
/// </summary>
private object ConvertToPropertyType(object value, Type targetType)
{
if (value == null) return null;
if (targetType.IsAssignableFrom(value.GetType())) return value;
try
{
return Convert.ChangeType(value, targetType);
}
catch
{
// 对于复杂类型或JsonElement,可能需要特殊处理
if (value is JsonElement je && targetType == typeof(string)) return je.ToString();
// 添加更多转换逻辑...
return null;
}
}
}
/// <summary>
/// 值转换器接口 (用于字典翻译、类型转换等)
/// </summary>
public interface IValueConverter
{
/// <summary>
/// 执行值转换
/// </summary>
/// <param name="sourceValue">源值</param>
/// <param name="sourceType">源类型字符串 (来自配置)</param>
/// <param name="targetType">目标类型字符串 (来自配置)</param>
/// <param name="sourceDictName">源字典名称 (来自配置)</param>
/// <param name="targetDictName">目标字典名称 (来自配置)</param>
/// <param name="paramDirection">参数方向 (1入参,2出参)</param>
/// <returns>转换后的值</returns>
object Convert(object sourceValue, string sourceType, string targetType, string sourceDictName, string targetDictName, int paramDirection);
object Convert(object sourceValue, decimal? oBJECT_FIELD_TYPE, decimal? sYSTEM_FIELD_TYPE, string oBJECT_DICT_NAME, string sYSTEM_DICT_NAME, int pARAMETR_TYPE);
}
/// <summary>
/// 默认的值转换器实现 (简单类型转换,无字典转换)
/// </summary>
public class DefaultValueConverter : IValueConverter
{
public object Convert(object sourceValue, string sourceType, string targetType, string sourceDictName, string targetDictName, int paramDirection)
{
// 简单示例:如果类型字符串匹配C#类型,尝试转换
if (sourceValue == null) return null;
try
{
Type targetTypeResolved = Type.GetType(targetType) ?? typeof(object);
return System.Convert.ChangeType(sourceValue, targetTypeResolved);
}
catch
{
return sourceValue;
}
}
public object Convert(object sourceValue, decimal? objectFieldType, decimal? systemFieldType, string objectDictName, string systemDictName, int paramDirection)
{
// 示例实现:直接返回源值,实际应用中需要根据字段类型和字典名称进行转换
return sourceValue;
}
}
}