合并代码
This commit is contained in:
commit
ac226110cd
@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@ -8,7 +9,7 @@ using System.Text;
|
||||
namespace JiShe.CollectBus.IncrementalGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 复杂类型源生成器
|
||||
/// 复杂类型增量源生成器
|
||||
/// </summary>
|
||||
[Generator(LanguageNames.CSharp)]
|
||||
public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
|
||||
@ -19,12 +20,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
||||
{
|
||||
//Debugger.Launch();
|
||||
|
||||
context.RegisterPostInitializationOutput(ctx =>
|
||||
{
|
||||
ctx.AddSource("GeneratorInit.g.cs", "// Initialization Marker");
|
||||
});
|
||||
|
||||
// 步骤1:筛选带有 [GenerateAccessors] 的类
|
||||
// 步骤1:筛选带有 [SourceAnalyzers] 的类
|
||||
var classDeclarations = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
predicate: static (s, _) => IsClassWithAttribute(s),
|
||||
@ -39,7 +35,6 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
||||
}
|
||||
|
||||
private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0;
|
||||
|
||||
|
||||
private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context)
|
||||
{
|
||||
@ -76,18 +71,24 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成代码
|
||||
/// </summary>
|
||||
/// <param name="compilation"></param>
|
||||
/// <param name="classes"></param>
|
||||
/// <param name="context"></param>
|
||||
private static void GenerateCode(
|
||||
Compilation compilation,
|
||||
IEnumerable<ClassDeclarationSyntax> classes,
|
||||
SourceProductionContext context)
|
||||
{
|
||||
var processedTypes = new HashSet<ITypeSymbol>(SymbolEqualityComparer.Default);
|
||||
|
||||
|
||||
if (!classes.Any())
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor("GEN002", "No Targets",
|
||||
"No classes with [GenerateAccessors] found", "Debug", DiagnosticSeverity.Warning, true),
|
||||
new DiagnosticDescriptor("GEN002", "没有目标类",
|
||||
"没有找到SourceAnalyzers标记的类", "Debug", DiagnosticSeverity.Warning, true),
|
||||
Location.None));
|
||||
}
|
||||
|
||||
@ -99,129 +100,39 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
||||
if (classSymbol == null || !processedTypes.Add(classSymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor("GEN003", "Invalid Symbol",
|
||||
$"Class symbol is null for {classDecl.Identifier.Text}", "Error", DiagnosticSeverity.Error, true),
|
||||
new DiagnosticDescriptor("GEN003", "无效符号",
|
||||
$"类名称为{classDecl.Identifier.Text} 符号为空", "Error", DiagnosticSeverity.Error, true),
|
||||
Location.None));
|
||||
continue;
|
||||
}
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
"PA001",
|
||||
"Generated Accessors",
|
||||
$"Generating accessors for {classSymbol.Name}",
|
||||
"Performance",
|
||||
DiagnosticSeverity.Info,
|
||||
true),
|
||||
Location.None));
|
||||
|
||||
// 新增:输出继承链信息
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor("HIERARCHY", "Class Hierarchy",
|
||||
$"Processing class: {classSymbol.Name}, BaseType: {classSymbol.BaseType?.Name}",
|
||||
"Debug", DiagnosticSeverity.Info, true),
|
||||
Location.None));
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor("PA002", "Class Found",
|
||||
$"Processing class: {classSymbol.Name}", "Debug", DiagnosticSeverity.Warning, true),
|
||||
Location.None));
|
||||
|
||||
var code = BuildAccessorsForType(classSymbol, compilation, processedTypes);
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"Generated code for {classSymbol.Name}:\n{code}"); // 调试输出
|
||||
|
||||
context.AddSource($"{classSymbol.Name}Extension.g.cs", code);
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildAccessorsForType(
|
||||
INamedTypeSymbol classSymbol,
|
||||
Compilation compilation,
|
||||
HashSet<ITypeSymbol> processedTypes)
|
||||
{
|
||||
var code = new StringBuilder();
|
||||
code.AppendLine("#pragma warning disable CS0419 // 禁用警告");
|
||||
code.AppendLine("// Generated code for " + classSymbol.Name);
|
||||
code.AppendLine("// <auto-generated/>");
|
||||
code.AppendLine("#nullable enable");
|
||||
code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
|
||||
code.AppendLine();
|
||||
|
||||
code.AppendLine($"public static class {classSymbol.Name}Extension{GetGenericParams(classSymbol)}");
|
||||
code.AppendLine("{");
|
||||
|
||||
//foreach (var prop in classSymbol.GetMembers().OfType<IPropertySymbol>())
|
||||
//{
|
||||
// if (prop.IsIndexer) continue;
|
||||
|
||||
// GeneratePropertyAccessors(prop, code, compilation, processedTypes);
|
||||
//}
|
||||
|
||||
foreach (var prop in GetAllPropertiesInHierarchy(classSymbol))
|
||||
{
|
||||
if (prop.IsIndexer) continue;
|
||||
GeneratePropertyAccessors(prop, code, compilation, processedTypes);
|
||||
|
||||
var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes);
|
||||
context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
|
||||
}
|
||||
|
||||
code.AppendLine("}");
|
||||
return code.ToString();
|
||||
// 生成工厂注册代码
|
||||
context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
|
||||
}
|
||||
|
||||
//private static string GetGenericParams(INamedTypeSymbol symbol)
|
||||
// => symbol.IsGenericType ? $"<{string.Join(", ", symbol.TypeParameters.Select(t => t.Name))}>" : "";
|
||||
|
||||
/// <summary>
|
||||
/// 获取泛型参数
|
||||
/// </summary>
|
||||
/// <param name="symbol"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetGenericParams(INamedTypeSymbol symbol)
|
||||
{
|
||||
if (!symbol.IsGenericType) return "";
|
||||
var parameters = symbol.TypeParameters.Select(t => t.Name);
|
||||
return $"<{string.Join(", ", parameters)}>";
|
||||
}
|
||||
|
||||
private static void GeneratePropertyAccessors(
|
||||
IPropertySymbol prop,
|
||||
StringBuilder code,
|
||||
Compilation compilation,
|
||||
HashSet<ITypeSymbol> processedTypes)
|
||||
{
|
||||
// 关键修复点1:安全类型转换
|
||||
if (prop.Type is not ITypeSymbol propType) return;
|
||||
|
||||
code.AppendLine($" // Processing property: {prop.Name}");
|
||||
|
||||
// 处理元组类型
|
||||
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
|
||||
{
|
||||
GenerateTupleAccessors(prop, tupleType, code);
|
||||
}
|
||||
else if (propType is INamedTypeSymbol namedType)
|
||||
{
|
||||
GenerateStandardAccessors(prop, namedType, code);
|
||||
ProcessNestedType(namedType, compilation, processedTypes);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateTupleAccessors(IPropertySymbol prop, INamedTypeSymbol tupleType, StringBuilder code)
|
||||
{
|
||||
var elements = tupleType.TupleElements;
|
||||
var parentType = prop.ContainingType.ToDisplayString();
|
||||
|
||||
for (int i = 0; i < elements.Length; i++)
|
||||
{
|
||||
var element = elements[i];
|
||||
if (element.Type is not ITypeSymbol elementType) continue;
|
||||
|
||||
var elementName = element.CorrespondingTupleField?.Name ?? $"Item{i + 1}";
|
||||
code.AppendLine($" public static {elementType.ToDisplayString()} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");
|
||||
|
||||
if (prop.SetMethod != null)
|
||||
{
|
||||
var assignments = elements.Select((e, idx) =>
|
||||
idx == i ? "value" : $"obj.{prop.Name}.{e.Name}");
|
||||
code.AppendLine($" public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType.ToDisplayString()} value) => obj.{prop.Name} = ({string.Join(", ", assignments)});");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成标准属性的访问器
|
||||
/// </summary>
|
||||
/// <param name="prop"></param>
|
||||
/// <param name="propType"></param>
|
||||
/// <param name="code"></param>
|
||||
private static void GenerateStandardAccessors(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code)
|
||||
{
|
||||
var parentType = prop.ContainingType.ToDisplayString();
|
||||
@ -232,23 +143,387 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
||||
code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void ProcessNestedType(ITypeSymbol typeSymbol, Compilation compilation, HashSet<ITypeSymbol> processedTypes)
|
||||
/// <summary>
|
||||
/// 构建实体访问器代码(支持泛型)
|
||||
/// </summary>
|
||||
private static string BuildAccessorsForSourceEntity(
|
||||
INamedTypeSymbol classSymbol,
|
||||
Compilation compilation,
|
||||
HashSet<ITypeSymbol> processedTypes)
|
||||
{
|
||||
if (typeSymbol is not INamedTypeSymbol namedType) return;
|
||||
if (!ShouldProcessNestedType(namedType)) return;
|
||||
if (!processedTypes.Add(namedType)) return;
|
||||
var code = new StringBuilder();
|
||||
code.AppendLine("// <auto-generated/>");
|
||||
code.AppendLine("#nullable enable");
|
||||
code.AppendLine("using System;");
|
||||
code.AppendLine("using System.Reflection;");
|
||||
code.AppendLine("using System.Collections.Generic;");
|
||||
code.AppendLine("using JiShe.CollectBus.Analyzers.Shared;");
|
||||
code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
|
||||
code.AppendLine();
|
||||
|
||||
var code = BuildAccessorsForType(namedType, compilation, processedTypes);
|
||||
// 处理泛型类型名称
|
||||
var accessibility = classSymbol.DeclaredAccessibility switch
|
||||
{
|
||||
Accessibility.Public => "public",
|
||||
_ => "internal"
|
||||
};
|
||||
|
||||
var genericParams = classSymbol.IsGenericType
|
||||
? $"<{string.Join(", ", classSymbol.TypeParameters.Select(t => t.Name))}>"
|
||||
: "";
|
||||
|
||||
code.AppendLine(
|
||||
$"{accessibility} sealed class {classSymbol.Name}Accessor{genericParams} " + // 保留泛型参数
|
||||
$": ISourceEntityAccessor<{classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>");
|
||||
|
||||
code.AppendLine("{");
|
||||
|
||||
var propList = GetAllPropertiesInHierarchy(classSymbol);
|
||||
|
||||
foreach (var prop in propList)
|
||||
{
|
||||
// 安全类型转换
|
||||
if (prop.Type is not ITypeSymbol propType) continue;
|
||||
|
||||
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
|
||||
{
|
||||
GenerateTupleAccessors(prop, tupleType, code, classSymbol);
|
||||
}
|
||||
else if (propType is INamedTypeSymbol namedType)
|
||||
{
|
||||
GenerateStandardAccessors(prop, namedType, code);
|
||||
}
|
||||
}
|
||||
|
||||
//生成当前类属性名称集合
|
||||
GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol);
|
||||
|
||||
//生成当前类属性信息集合
|
||||
GeneratePropertyInfoListForSourceEntity(
|
||||
propList,
|
||||
code,
|
||||
compilation,
|
||||
classSymbol);
|
||||
|
||||
|
||||
//生成当前类属性访问
|
||||
GetGeneratePropertyValueForSourceEntity(
|
||||
propList,
|
||||
code,
|
||||
compilation,
|
||||
classSymbol);
|
||||
|
||||
//生成当前类属性设置
|
||||
SetGeneratePropertyValueForSourceEntity(
|
||||
propList,
|
||||
code,
|
||||
compilation,
|
||||
classSymbol);
|
||||
|
||||
code.AppendLine("}");
|
||||
return code.ToString();
|
||||
}
|
||||
|
||||
private static bool ShouldProcessNestedType(INamedTypeSymbol symbol)
|
||||
/// <summary>
|
||||
/// 生成泛型ValueTuple 元组访问器
|
||||
/// </summary>
|
||||
private static void GenerateTupleAccessors(
|
||||
IPropertySymbol prop,
|
||||
INamedTypeSymbol tupleType,
|
||||
StringBuilder code,
|
||||
INamedTypeSymbol classSymbol)
|
||||
{
|
||||
return symbol.DeclaredAccessibility == Accessibility.Public &&
|
||||
!symbol.IsTupleType &&
|
||||
!symbol.IsAnonymousType &&
|
||||
!symbol.IsImplicitlyDeclared &&
|
||||
!symbol.Name.StartsWith("<");
|
||||
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var tupleElements = tupleType.TupleElements;
|
||||
|
||||
for (int i = 0; i < tupleElements.Length; i++)
|
||||
{
|
||||
var element = tupleElements[i];
|
||||
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var elementName = element.Name;
|
||||
|
||||
// Getter保持不变
|
||||
code.AppendLine(
|
||||
$" public static {elementType} Get{prop.Name}_{elementName}" +
|
||||
$"({parentType} obj) => obj.{prop.Name}.{elementName};");
|
||||
|
||||
// Setter修复:使用元组字面量
|
||||
if (prop.SetMethod != null)
|
||||
{
|
||||
var valueExpressions = tupleElements.Select((e, idx) =>
|
||||
idx == i ? "value" : $"obj.{prop.Name}.{e.Name}"
|
||||
).ToList();
|
||||
|
||||
// 关键修复:生成正确的元组字面量表达式
|
||||
code.AppendLine(
|
||||
$" public static void Set{prop.Name}_{elementName}" +
|
||||
$"({parentType} obj, {elementType} value) => " +
|
||||
$"obj.{prop.Name} = ({string.Join(", ", valueExpressions)});");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理System.Tuple类型的访问器生成
|
||||
/// </summary>
|
||||
private static void GenerateSystemTupleAccessors(
|
||||
IPropertySymbol prop,
|
||||
INamedTypeSymbol tupleType,
|
||||
StringBuilder code,
|
||||
INamedTypeSymbol classSymbol)
|
||||
{
|
||||
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var elementTypes = tupleType.TypeArguments;
|
||||
var tupleTypeName = tupleType.ToDisplayString();
|
||||
|
||||
for (int i = 0; i < elementTypes.Length; i++)
|
||||
{
|
||||
var elementType = elementTypes[i].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
var elementName = $"Item{i + 1}";
|
||||
|
||||
// Getter
|
||||
code.AppendLine(
|
||||
$" public static {elementType} Get{prop.Name}_{elementName}" +
|
||||
$"({parentType} obj) => obj.{prop.Name}.{elementName};");
|
||||
|
||||
// Setter
|
||||
if (prop.SetMethod != null)
|
||||
{
|
||||
var assignments = elementTypes.Select((_, idx) =>
|
||||
idx == i ? "value" : $"obj.{prop.Name}.Item{idx + 1}"
|
||||
).ToList();
|
||||
|
||||
code.AppendLine(
|
||||
$" public static void Set{prop.Name}_{elementName}" +
|
||||
$"({parentType} obj, {elementType} value) => " +
|
||||
$"obj.{prop.Name} = new {tupleTypeName}({string.Join(", ", assignments)});");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增强的工厂类实现
|
||||
/// </summary>
|
||||
private static string BuildFactoryCode()
|
||||
{
|
||||
return """
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace JiShe.CollectBus.Analyzers.Shared;
|
||||
|
||||
public static class SourceEntityAccessorFactory
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, object> _accessors = new();
|
||||
|
||||
public static ISourceEntityAccessor<T> GetAccessor<T>()
|
||||
{
|
||||
return (ISourceEntityAccessor<T>)_accessors.GetOrAdd(typeof(T), t =>
|
||||
{
|
||||
// 获取泛型类型定义信息(如果是泛型类型)
|
||||
var isGeneric = t.IsGenericType;
|
||||
var genericTypeDef = isGeneric ? t.GetGenericTypeDefinition() : null;
|
||||
var arity = isGeneric ? genericTypeDef!.GetGenericArguments().Length : 0;
|
||||
|
||||
// 构建访问器类名
|
||||
var typeName = isGeneric
|
||||
? $"{t.Namespace}.{genericTypeDef!.Name.Split('`')[0]}Accessor`{arity}"
|
||||
: $"{t.Namespace}.{t.Name}Accessor";
|
||||
|
||||
// 尝试从当前程序集加载
|
||||
var accessorType = Assembly.GetAssembly(t)!.GetType(typeName)
|
||||
?? throw new InvalidOperationException($"Accessor type {typeName} not found");
|
||||
|
||||
// 处理泛型参数
|
||||
if (isGeneric && accessorType.IsGenericTypeDefinition)
|
||||
{
|
||||
accessorType = accessorType.MakeGenericType(t.GetGenericArguments());
|
||||
}
|
||||
|
||||
return Activator.CreateInstance(accessorType)!;
|
||||
});
|
||||
}
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 属性访问生成逻辑
|
||||
/// </summary>
|
||||
/// <param name="propList">属性集合</param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="compilation"></param>
|
||||
/// <param name="classSymbol"></param>
|
||||
private static void GetGeneratePropertyValueForSourceEntity(
|
||||
IEnumerable<IPropertySymbol> propList,
|
||||
StringBuilder code,
|
||||
Compilation compilation,
|
||||
INamedTypeSymbol classSymbol)
|
||||
{
|
||||
code.AppendLine($" public object GetPropertyValue({classSymbol} targetEntity, string propertyName)");
|
||||
code.AppendLine(" {");
|
||||
code.AppendLine(" return propertyName switch");
|
||||
code.AppendLine(" {");
|
||||
|
||||
foreach (var prop in propList)
|
||||
{
|
||||
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
||||
{
|
||||
foreach (var element in tupleType.TupleElements)
|
||||
{
|
||||
code.AppendLine(
|
||||
$" \"{prop.Name}.{element.Name}\" => " +
|
||||
$"Get{prop.Name}_{element.Name}(targetEntity),");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
code.AppendLine(
|
||||
$" \"{prop.Name}\" => " +
|
||||
$"Get{prop.Name}(targetEntity),");
|
||||
}
|
||||
}
|
||||
|
||||
code.AppendLine(" _ => throw new ArgumentException($\"Unknown property: {propertyName}\")");
|
||||
code.AppendLine(" };");
|
||||
code.AppendLine(" }");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 属性设置生成逻辑
|
||||
/// </summary>
|
||||
/// <param name="propList">属性集合</param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="compilation"></param>
|
||||
/// <param name="classSymbol"></param>
|
||||
private static void SetGeneratePropertyValueForSourceEntity(
|
||||
IEnumerable<IPropertySymbol> propList,
|
||||
StringBuilder code,
|
||||
Compilation compilation,
|
||||
INamedTypeSymbol classSymbol)
|
||||
{
|
||||
code.AppendLine($" public void SetPropertyValue({classSymbol} targetEntity, string propertyName, object value)");
|
||||
code.AppendLine(" {");
|
||||
code.AppendLine(" switch (propertyName)");
|
||||
code.AppendLine(" {");
|
||||
|
||||
foreach (var prop in propList)
|
||||
{
|
||||
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
||||
{
|
||||
foreach (var element in tupleType.TupleElements)
|
||||
{
|
||||
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
code.AppendLine($" case \"{prop.Name}.{element.Name}\":");
|
||||
code.AppendLine($" Set{prop.Name}_{element.Name}(");
|
||||
code.AppendLine($" targetEntity, ({elementType})value);");
|
||||
code.AppendLine(" break;");
|
||||
}
|
||||
}
|
||||
else if (prop.SetMethod != null)
|
||||
{
|
||||
var propType = prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
code.AppendLine($" case \"{prop.Name}\":");
|
||||
code.AppendLine($" Set{prop.Name}(");
|
||||
code.AppendLine($" targetEntity, ({propType})value);");
|
||||
code.AppendLine(" break;");
|
||||
}
|
||||
}
|
||||
|
||||
code.AppendLine(" default:");
|
||||
code.AppendLine(" throw new ArgumentException($\"Unknown property: {propertyName}\");");
|
||||
code.AppendLine(" }");
|
||||
code.AppendLine(" }");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 属性名称集合
|
||||
/// </summary>
|
||||
/// <param name="propList">属性集合</param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="compilation"></param>
|
||||
/// <param name="classSymbol"></param>
|
||||
private static void GeneratePropertyListForSourceEntity(
|
||||
IEnumerable<IPropertySymbol> propList,
|
||||
StringBuilder code,
|
||||
Compilation compilation,
|
||||
INamedTypeSymbol classSymbol)
|
||||
{
|
||||
code.AppendLine(" public List<string> PropertyNameList {get;} = new List<string>()");
|
||||
code.AppendLine(" {");
|
||||
List<string> tempPropList = new List<string>();
|
||||
foreach (var prop in propList)
|
||||
{
|
||||
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
||||
{
|
||||
foreach (var element in tupleType.TupleElements)
|
||||
{
|
||||
tempPropList.Add($"\"{prop.Name}.{element.Name}\"");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempPropList.Add($"\"{prop.Name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
code.Append(string.Join(",", tempPropList));
|
||||
|
||||
code.AppendLine(" };");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成当前类属性信息集合(支持嵌套元组)
|
||||
/// </summary>
|
||||
private static void GeneratePropertyInfoListForSourceEntity(
|
||||
IEnumerable<IPropertySymbol> propList,
|
||||
StringBuilder code,
|
||||
Compilation compilation,
|
||||
INamedTypeSymbol classSymbol)
|
||||
{
|
||||
code.AppendLine(" public List<System.Reflection.PropertyInfo> PropertyInfoList { get; } = new List<System.Reflection.PropertyInfo>");
|
||||
code.AppendLine(" {");
|
||||
|
||||
var initializerLines = new List<string>();
|
||||
|
||||
foreach (var prop in propList)
|
||||
{
|
||||
// 主属性
|
||||
AddPropertyInitializer(classSymbol, prop, initializerLines);
|
||||
|
||||
// 处理元组嵌套属性
|
||||
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
||||
{
|
||||
foreach (var element in tupleType.TupleElements)
|
||||
{
|
||||
// 生成形如:typeof(ValueTuple<string,T>).GetProperty("Item1")
|
||||
var tupleTypeName = tupleType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
initializerLines.Add(
|
||||
$"typeof({tupleTypeName}).GetProperty(\"{element.Name}\") ?? " +
|
||||
$"throw new InvalidOperationException(\"Tuple element {element.Name} not found\")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code.AppendLine(string.Join(",\n", initializerLines));
|
||||
code.AppendLine(" };");
|
||||
}
|
||||
|
||||
private static void AddPropertyInitializer(
|
||||
INamedTypeSymbol classSymbol,
|
||||
IPropertySymbol prop,
|
||||
List<string> initializerLines)
|
||||
{
|
||||
var classType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
initializerLines.Add(
|
||||
$"typeof({classType}).GetProperty(\"{prop.Name}\", " +
|
||||
"System.Reflection.BindingFlags.Public | " +
|
||||
"System.Reflection.BindingFlags.Instance) ?? " +
|
||||
$"throw new InvalidOperationException(\"Property {prop.Name} not found\")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,6 @@ namespace JiShe.CollectBus.IoTDB.Model
|
||||
/// 单项数据键值对
|
||||
/// </summary>
|
||||
[SingleMeasuring(nameof(SingleColumn))]
|
||||
public required Tuple<string, T> SingleColumn { get; set; }
|
||||
public required ValueTuple<string, T> SingleColumn { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,6 @@ namespace JiShe.CollectBus.IoTDB.Model
|
||||
/// 单项数据键值对
|
||||
/// </summary>
|
||||
[SingleMeasuring(nameof(SingleMeasuring))]
|
||||
public required Tuple<string, T> SingleMeasuring { get; set; }
|
||||
public required ValueTuple<string, T> SingleMeasuring { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ using JiShe.CollectBus.IoTDB.Options;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Domain.Entities;
|
||||
using JiShe.CollectBus.Analyzers.Shared;
|
||||
|
||||
namespace JiShe.CollectBus.IoTDB.Provider
|
||||
{
|
||||
@ -176,6 +177,8 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
||||
/// <returns></returns>
|
||||
public async Task<DeviceMetadata> GetMetadata<T>() where T : IoTEntity
|
||||
{
|
||||
var accessor = SourceEntityAccessorFactory.GetAccessor<T>();
|
||||
|
||||
var columns = CollectColumnMetadata(typeof(T));
|
||||
var metadata = BuildDeviceMetadata<T>(columns);
|
||||
var metaData = MetadataCache.AddOrUpdate(
|
||||
@ -260,6 +263,8 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
||||
List<string> tempColumnNames = new List<string>();
|
||||
tempColumnNames.AddRange(metadata.ColumnNames);
|
||||
|
||||
var accessor = SourceEntityAccessorFactory.GetAccessor<T>();
|
||||
|
||||
var entityTypeAttribute = typeof(T).GetCustomAttribute<EntityTypeAttribute>();
|
||||
|
||||
if (entityTypeAttribute == null)
|
||||
@ -295,69 +300,74 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
||||
|
||||
foreach (var measurement in tempColumnNames)
|
||||
{
|
||||
|
||||
PropertyInfo propertyInfo = typeof(T).GetProperty(measurement);
|
||||
if (propertyInfo == null)
|
||||
{
|
||||
throw new Exception($"{nameof(BuildTablet)} 构建表模型{typeof(T).Name}时,没有找到{measurement}属性,属于异常情况,-101。");
|
||||
}
|
||||
|
||||
var value = propertyInfo.GetValue(entity);
|
||||
if (propertyInfo.IsDefined(typeof(SingleMeasuringAttribute), false) && metadata.IsSingleMeasuring == true)//表示当前对象是单测点模式
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
Type tupleType = value.GetType();
|
||||
Type[] tupleArgs = tupleType.GetGenericArguments();
|
||||
Type item2Type = tupleArgs[1]; // T 的实际类型
|
||||
var item1 = tupleType.GetProperty("Item1")!.GetValue(value);
|
||||
var item2 = tupleType.GetProperty("Item2")!.GetValue(value);
|
||||
if (item1 == null || item2 == null)
|
||||
{
|
||||
throw new Exception($"{nameof(BuildTablet)} 构建表模型{typeof(T).Name}时,单测点模式构建失败,没有获取测点名称或者测点值,-102。");
|
||||
}
|
||||
|
||||
var indexOf = metadata.ColumnNames.IndexOf(measurement);
|
||||
metadata.ColumnNames[indexOf] = (string)item1!;
|
||||
|
||||
rowValues.Add(item2);
|
||||
}
|
||||
else
|
||||
{
|
||||
rowValues.Add(null);
|
||||
}
|
||||
|
||||
//同时如果是单测点模式,且是table模型存储,路径只能通过DevicePathBuilder.GetDeviceTableName(entity)获取
|
||||
if (_runtimeContext.UseTableSessionPool)
|
||||
{
|
||||
tableNameOrTreePath = DevicePathBuilder.GetDeviceTableName(entity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//需要根据value的类型,进行相应的值映射转换,例如datetime转换为long的时间戳值
|
||||
if (value != null)
|
||||
{
|
||||
Type tupleType = value.GetType();
|
||||
var tempValue = tupleType.Name.ToUpper() switch
|
||||
{
|
||||
"DATETIME" => Convert.ToDateTime(value).GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
||||
_ => value
|
||||
};
|
||||
|
||||
rowValues.Add(tempValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
rowValues.Add(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rowValues.Add(accessor.GetPropertyValue(entity,measurement));
|
||||
}
|
||||
|
||||
values.Add(rowValues);
|
||||
//foreach (var measurement in tempColumnNames)
|
||||
//{
|
||||
|
||||
// PropertyInfo propertyInfo = typeof(T).GetProperty(measurement);
|
||||
// if (propertyInfo == null)
|
||||
// {
|
||||
// throw new Exception($"{nameof(BuildTablet)} 构建表模型{typeof(T).Name}时,没有找到{measurement}属性,属于异常情况,-101。");
|
||||
// }
|
||||
|
||||
// var value = propertyInfo.GetValue(entity);
|
||||
// if (propertyInfo.IsDefined(typeof(SingleMeasuringAttribute), false) && metadata.IsSingleMeasuring == true)//表示当前对象是单测点模式
|
||||
// {
|
||||
// if (value != null)
|
||||
// {
|
||||
// Type tupleType = value.GetType();
|
||||
// Type[] tupleArgs = tupleType.GetGenericArguments();
|
||||
// Type item2Type = tupleArgs[1]; // T 的实际类型
|
||||
// var item1 = tupleType.GetProperty("Item1")!.GetValue(value);
|
||||
// var item2 = tupleType.GetProperty("Item2")!.GetValue(value);
|
||||
// if (item1 == null || item2 == null)
|
||||
// {
|
||||
// throw new Exception($"{nameof(BuildTablet)} 构建表模型{typeof(T).Name}时,单测点模式构建失败,没有获取测点名称或者测点值,-102。");
|
||||
// }
|
||||
|
||||
// var indexOf = metadata.ColumnNames.IndexOf(measurement);
|
||||
// metadata.ColumnNames[indexOf] = (string)item1!;
|
||||
|
||||
// rowValues.Add(item2);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// rowValues.Add(null);
|
||||
// }
|
||||
|
||||
// //同时如果是单测点模式,且是table模型存储,路径只能通过DevicePathBuilder.GetDeviceTableName(entity)获取
|
||||
// if (_runtimeContext.UseTableSessionPool)
|
||||
// {
|
||||
// tableNameOrTreePath = DevicePathBuilder.GetDeviceTableName(entity);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
|
||||
// //需要根据value的类型,进行相应的值映射转换,例如datetime转换为long的时间戳值
|
||||
// if (value != null)
|
||||
// {
|
||||
// Type tupleType = value.GetType();
|
||||
// var tempValue = tupleType.Name.ToUpper() switch
|
||||
// {
|
||||
// "DATETIME" => Convert.ToDateTime(value).GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
||||
// _ => value
|
||||
// };
|
||||
|
||||
// rowValues.Add(tempValue);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// rowValues.Add(value);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
values.Add(rowValues);
|
||||
|
||||
//如果指定了路径
|
||||
if (!string.IsNullOrWhiteSpace(tableNameOrTreePath))
|
||||
@ -556,6 +566,8 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
||||
//metadata.ColumnNames.Insert(0, "Timestamps");
|
||||
//metadata.DataTypes.Insert(0, TSDataType.TIMESTAMP);
|
||||
|
||||
var accessor = SourceEntityAccessorFactory.GetAccessor<T>();
|
||||
|
||||
while (dataSet.HasNext() && results.Count < pageSize)
|
||||
{
|
||||
var record = dataSet.Next();
|
||||
@ -578,11 +590,14 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
||||
|
||||
if (measurement.ToLower().EndsWith("time"))
|
||||
{
|
||||
typeof(T).GetProperty(measurement)?.SetValue(entity, TimestampHelper.ConvertToDateTime(tempValue, TimestampUnit.Nanoseconds));
|
||||
//typeof(T).GetProperty(measurement)?.SetValue(entity, TimestampHelper.ConvertToDateTime(tempValue, TimestampUnit.Nanoseconds));
|
||||
|
||||
accessor.SetPropertyValue(entity, measurement, TimestampHelper.ConvertToDateTime(tempValue, TimestampUnit.Nanoseconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
typeof(T).GetProperty(measurement)?.SetValue(entity, tempValue);
|
||||
accessor.SetPropertyValue(entity, measurement, tempValue);
|
||||
//typeof(T).GetProperty(measurement)?.SetValue(entity, tempValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
||||
DeviceType = $"{data.DeviceType.ToString()}.{IOTDBDataType.Data}",
|
||||
ProjectId = $"{data.ProjectId}",
|
||||
Timestamps = data.TimeSpan!.Value.GetFormatTime(analysisBaseDto.DensityUnit, analysisBaseDto.TimeDensity).GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
||||
SingleMeasuring = new Tuple<string, T>(data.FiledName ?? string.Empty, data.DataValue ?? default)
|
||||
SingleMeasuring = (data.FiledName ?? string.Empty, data.DataValue ?? default)
|
||||
};
|
||||
_runtimeContext.UseTableSessionPool = true; // 使用表模型池
|
||||
var taskSendInfo = await _dbProvider.QueryAsync<MeterReadingTelemetryPacketInfo>(new IoTDBQueryOptions() { TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(), Conditions = conditions, PageIndex = 0, PageSize = 1 });
|
||||
@ -199,7 +199,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
||||
DeviceType = $"{item.DeviceType}.{IOTDBDataType.Data}",
|
||||
ProjectId = $"{item.ProjectId}",
|
||||
Timestamps = item.TimeSpan!.Value.GetFormatTime(analysisBaseDto.DensityUnit, analysisBaseDto.TimeDensity).GetDateTimeOffset().ToUnixTimeNanoseconds(), // TODO:这里暂时格式化15分钟数据,需要进行调整
|
||||
SingleMeasuring = new Tuple<string, T>(item.FiledName ?? string.Empty, item.DataValue ?? default)
|
||||
SingleMeasuring =(item.FiledName ?? string.Empty, item.DataValue ?? default)
|
||||
};
|
||||
_runtimeContext.UseTableSessionPool = true; // 使用表模型池
|
||||
var taskSendInfo = await _dbProvider.QueryAsync<MeterReadingTelemetryPacketInfo>(new IoTDBQueryOptions() { TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(), Conditions = conditions, PageIndex = 0, PageSize = 1 });
|
||||
@ -283,7 +283,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
||||
DeviceType = $"{data.DeviceType}.{IOTDBDataType.Status}",
|
||||
ProjectId = $"{data.ProjectId}",
|
||||
Timestamps = timestamps,
|
||||
SingleMeasuring = new Tuple<string, T>(data.FiledName!, data.DataValue!)
|
||||
SingleMeasuring = (data.FiledName!, data.DataValue!)
|
||||
};
|
||||
_runtimeContext.UseTableSessionPool = false; // 使树模型池
|
||||
await _dbProvider.InsertAsync(treeData);
|
||||
@ -295,7 +295,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
||||
DeviceType = $"{data.DeviceType}.{IOTDBDataType.Status}",
|
||||
ProjectId = $"{data.ProjectId}",
|
||||
Timestamps = timestamps,
|
||||
SingleMeasuring = new Tuple<string, string>(ConcentratorStatusFieldConst.FrameData, analysisBaseDto.HexMessage ?? string.Empty)
|
||||
SingleMeasuring = (ConcentratorStatusFieldConst.FrameData, analysisBaseDto.HexMessage ?? string.Empty)
|
||||
};
|
||||
|
||||
_runtimeContext.UseTableSessionPool = false; // 使树模型池
|
||||
@ -309,7 +309,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
||||
DeviceType = $"{data.DeviceType}.{IOTDBDataType.Status}",
|
||||
ProjectId = $"{data.ProjectId}",
|
||||
Timestamps = timestamps,
|
||||
SingleMeasuring = new Tuple<string, long>(ConcentratorStatusFieldConst.RecordingTime, (data.TimeSpan.HasValue ? data.TimeSpan.Value : DateTime.Now).GetDateTimeOffset().ToUnixTimeNanoseconds())
|
||||
SingleMeasuring = (ConcentratorStatusFieldConst.RecordingTime, (data.TimeSpan.HasValue ? data.TimeSpan.Value : DateTime.Now).GetDateTimeOffset().ToUnixTimeNanoseconds())
|
||||
};
|
||||
_runtimeContext.UseTableSessionPool = false; // 使树模型池
|
||||
await _dbProvider.InsertAsync(treeRecordingTimeData);
|
||||
@ -321,7 +321,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
||||
DeviceType = $"{data.DeviceType}.{IOTDBDataType.Status}",
|
||||
ProjectId = $"{data.ProjectId}",
|
||||
Timestamps = timestamps,
|
||||
SingleMeasuring = new Tuple<string, string>(ConcentratorStatusFieldConst.Remark, data.FiledDesc ?? string.Empty)
|
||||
SingleMeasuring = (ConcentratorStatusFieldConst.Remark, data.FiledDesc ?? string.Empty)
|
||||
};
|
||||
_runtimeContext.UseTableSessionPool = false; // 使树模型池
|
||||
await _dbProvider.InsertAsync(treeRemarkData);
|
||||
|
||||
@ -730,7 +730,6 @@ namespace JiShe.CollectBus.Protocol.T37612012
|
||||
List<string> values = new List<string>() { $"{dataTime:yy}", $"{dataTime:MM}", $"{dataTime:dd}", $"{dataTime:HH}", $"{dataTime:mm}", };
|
||||
values.Reverse();
|
||||
return values;
|
||||
//return string.Join("", values);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@ -125,13 +125,13 @@ namespace JiShe.CollectBus.DataChannels
|
||||
// 批量写入数据库
|
||||
await _dbProvider.BatchInsertAsync(metadata, records);
|
||||
|
||||
// 限流推送Kafka
|
||||
await DeviceGroupBalanceControl.ProcessWithThrottleAsync(
|
||||
items: records,
|
||||
deviceIdSelector: data => data.DeviceId,
|
||||
processor: async (data, groupIndex) =>
|
||||
await KafkaProducerIssuedMessageAction(topicName, data, groupIndex)
|
||||
);
|
||||
//// 限流推送Kafka
|
||||
//await DeviceGroupBalanceControl.ProcessWithThrottleAsync(
|
||||
// items: records,
|
||||
// deviceIdSelector: data => data.DeviceId,
|
||||
// processor: async (data, groupIndex) =>
|
||||
// await KafkaProducerIssuedMessageAction(topicName, data, groupIndex)
|
||||
//);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@ -53,6 +53,10 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
[HttpGet]
|
||||
public async Task UseSessionPool(long testTime)
|
||||
{
|
||||
var dataTime = DateTime.Now;
|
||||
|
||||
List<string> values = new List<string>() { $"{dataTime:yy}", $"{dataTime:MM}", $"{dataTime:dd}", $"{dataTime:HH}", $"{dataTime:mm}", };
|
||||
|
||||
|
||||
ElectricityMeterTreeModel meter = new ElectricityMeterTreeModel()
|
||||
{
|
||||
@ -67,6 +71,11 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
Timestamps = testTime// DateTimeOffset.UtcNow.ToUnixTimeNanoseconds()//testTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
||||
};
|
||||
//ElectricityMeterTreeModelExtension.GetCurrent()
|
||||
//SourceEntityAccessorFactory.SetCurrent(meter);
|
||||
|
||||
//ElectricityMeterTreeModelAccessor.
|
||||
//TableModelSingleMeasuringEntityExtension
|
||||
//TableModelSingleMeasuringEntityAccessor.GetSystemName(meter);
|
||||
await _iotDBProvider.InsertAsync(meter);
|
||||
}
|
||||
|
||||
@ -165,6 +174,8 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
[HttpGet]
|
||||
public async Task TestTreeModelSingleMeasuringEntity(string measuring, string value, DateTime time)
|
||||
{
|
||||
time = DateTime.Now;
|
||||
|
||||
var meter = new TreeModelSingleMeasuringEntity<string>()
|
||||
{
|
||||
SystemName = "energy",
|
||||
@ -172,7 +183,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
DeviceType = "1",
|
||||
ProjectId = "10059",
|
||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||
SingleMeasuring = new Tuple<string, string>(measuring, value)
|
||||
SingleMeasuring = (measuring, value)
|
||||
};
|
||||
await _iotDBProvider.InsertAsync(meter);
|
||||
}
|
||||
@ -185,6 +196,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
[HttpGet]
|
||||
public async Task TestTreeModelSingleMeasuringEntity2(string measuring, int value, DateTime time)
|
||||
{
|
||||
time = DateTime.Now;
|
||||
var meter = new TreeModelSingleMeasuringEntity<int>()
|
||||
{
|
||||
SystemName = "energy",
|
||||
@ -192,7 +204,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
DeviceType = "Ammeter",
|
||||
ProjectId = "10059",
|
||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||
SingleMeasuring = new Tuple<string, int>(measuring, value)
|
||||
SingleMeasuring = (measuring, value)
|
||||
};
|
||||
await _iotDBProvider.InsertAsync(meter);
|
||||
}
|
||||
@ -205,6 +217,8 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
[HttpGet]
|
||||
public async Task TestTableModelSingleMeasuringEntity(string measuring, string value, DateTime time)
|
||||
{
|
||||
time = DateTime.Now;
|
||||
|
||||
var meter = new TableModelSingleMeasuringEntity<string>()
|
||||
{
|
||||
SystemName = "energy",
|
||||
@ -212,7 +226,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
DeviceType = "Ammeter",
|
||||
ProjectId = "10059",
|
||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||
SingleColumn = new Tuple<string, string>(measuring, value)
|
||||
SingleColumn = (measuring, value)
|
||||
};
|
||||
_dbContext.UseTableSessionPool = true;
|
||||
await _iotDBProvider.InsertAsync(meter);
|
||||
@ -226,6 +240,8 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
[HttpGet]
|
||||
public async Task TestTableModelSingleMeasuringEntity2(string measuring, int value, DateTime time)
|
||||
{
|
||||
time = DateTime.Now;
|
||||
|
||||
var meter = new TableModelSingleMeasuringEntity<int>()
|
||||
{
|
||||
SystemName = "energy",
|
||||
@ -233,7 +249,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
||||
DeviceType = "Ammeter",
|
||||
ProjectId = "10059",
|
||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||
SingleColumn = new Tuple<string, int>(measuring, value)
|
||||
SingleColumn = (measuring, value)
|
||||
};
|
||||
_dbContext.UseTableSessionPool = true;
|
||||
await _iotDBProvider.InsertAsync(meter);
|
||||
|
||||
@ -262,7 +262,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
||||
//_logger.LogWarning($"电表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
||||
return;
|
||||
}
|
||||
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, Tuple.Create(ProtocolConst.AmmeterSubscriberWorkerAutoValveControlIssuedEventName, tempTask));
|
||||
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, Tuple.Create(ProtocolConst.AmmeterSubscriberWorkerFifteenMinuteIssuedEventName, tempTask));
|
||||
});
|
||||
}
|
||||
else if (meteryType == MeterTypeEnum.WaterMeter.ToString())
|
||||
|
||||
@ -6,7 +6,7 @@ using JiShe.CollectBus.IoTDB.Model;
|
||||
namespace JiShe.CollectBus.Ammeters
|
||||
{
|
||||
[EntityType(EntityTypeEnum.TableModel)]
|
||||
[SourceAnalyzers]
|
||||
//[SourceAnalyzers]
|
||||
public class ElectricityMeter : IoTEntity
|
||||
{
|
||||
[ATTRIBUTEColumn]
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using JiShe.CollectBus.IoTDB.Attribute;
|
||||
using JiShe.CollectBus.IoTDB.Enums;
|
||||
using JiShe.CollectBus.IoTDB.Model;
|
||||
using System;
|
||||
|
||||
namespace JiShe.CollectBus.Ammeters
|
||||
{
|
||||
@ -35,5 +36,7 @@ namespace JiShe.CollectBus.Ammeters
|
||||
|
||||
[FIELDColumn]
|
||||
public double? Currentd { get; set; }
|
||||
|
||||
public Tuple<int,string> TupleData { get; set;}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace JiShe.CollectBus.Analyzers
|
||||
namespace JiShe.CollectBus.Analyzers.Shared
|
||||
{
|
||||
public interface ISourceAnalyzersProvider<T>
|
||||
public interface ISourceEntityAccessor<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取属性值
|
||||
@ -23,18 +24,13 @@ namespace JiShe.CollectBus.Analyzers
|
||||
void SetPropertyValue(T entity, string propertyName, object value);
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否是元组属性
|
||||
/// 属性名称集合
|
||||
/// </summary>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <returns></returns>
|
||||
bool IsTupleProperty(string propertyName);
|
||||
List<string> PropertyNameList { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取元组属性值
|
||||
/// 属性信息集合
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="tuplePropertyName"></param>
|
||||
/// <returns></returns>
|
||||
(object Item1, object Item2) GetTupleParts(T entity, string tuplePropertyName);
|
||||
List<PropertyInfo> PropertyInfoList { get; }
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user