Compare commits
No commits in common. "ff517664fe1091c8011f0432f11192722c654be4" and "53e6bb252ab74375010fbe6877ce5ced5590e47d" have entirely different histories.
ff517664fe
...
53e6bb252a
@ -1,6 +1,5 @@
|
|||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -9,17 +8,19 @@ using System.Text;
|
|||||||
namespace JiShe.CollectBus.IncrementalGenerator
|
namespace JiShe.CollectBus.IncrementalGenerator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 复杂类型增量源生成器
|
/// 复杂类型源生成器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Generator(LanguageNames.CSharp)]
|
[Generator(LanguageNames.CSharp)]
|
||||||
public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
|
public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
|
||||||
{
|
{
|
||||||
private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute";
|
private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute";
|
||||||
|
private const string SourceEntityAccessorFactoryNamespace = "JiShe.CollectBus.Analyzers.Shared";
|
||||||
|
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
//Debugger.Launch();
|
//Debugger.Launch();
|
||||||
|
|
||||||
|
|
||||||
// 步骤1:筛选带有 [SourceAnalyzers] 的类
|
// 步骤1:筛选带有 [SourceAnalyzers] 的类
|
||||||
var classDeclarations = context.SyntaxProvider
|
var classDeclarations = context.SyntaxProvider
|
||||||
.CreateSyntaxProvider(
|
.CreateSyntaxProvider(
|
||||||
@ -31,11 +32,11 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
|||||||
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
|
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
|
||||||
|
|
||||||
context.RegisterSourceOutput(compilationAndClasses, (spc, source) =>
|
context.RegisterSourceOutput(compilationAndClasses, (spc, source) =>
|
||||||
GenerateCode(source.Left, source.Right!, spc));
|
GenerateCode(source.Left, source.Right!, spc));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0;
|
private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0;
|
||||||
|
|
||||||
private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context)
|
private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context)
|
||||||
{
|
{
|
||||||
var classDecl = (ClassDeclarationSyntax)context.Node;
|
var classDecl = (ClassDeclarationSyntax)context.Node;
|
||||||
@ -105,15 +106,129 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
|||||||
Location.None));
|
Location.None));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes);
|
//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);
|
||||||
|
|
||||||
|
|
||||||
|
var code3 = BuildAccessorsForType2(classSymbol, compilation, processedTypes);
|
||||||
context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
|
context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
|
||||||
|
|
||||||
|
//code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
|
||||||
|
//if (classSymbol.ContainingNamespace.ToDisplayString() == "JiShe.CollectBus.IoTDB")
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成工厂注册代码
|
// 生成工厂注册代码
|
||||||
context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
|
context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建类的属性访问器代码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="classSymbol"></param>
|
||||||
|
/// <param name="compilation"></param>
|
||||||
|
/// <param name="processedTypes"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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 GetAllPropertiesInHierarchy(classSymbol))
|
||||||
|
{
|
||||||
|
if (prop.IsIndexer) continue;
|
||||||
|
GeneratePropertyAccessorsForType(prop, code, compilation, processedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
code.AppendLine("}");
|
||||||
|
return code.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建类的属性访问器代码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="classSymbol"></param>
|
||||||
|
/// <param name="compilation"></param>
|
||||||
|
/// <param name="processedTypes"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string BuildAccessorsForType2(
|
||||||
|
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 sealed class {classSymbol.Name}Accessor : ISourceEntityAccessor<{classSymbol.Name}>");
|
||||||
|
code.AppendLine("{");
|
||||||
|
|
||||||
|
foreach (var prop in GetAllPropertiesInHierarchy(classSymbol))
|
||||||
|
{
|
||||||
|
if (prop.IsIndexer) continue;
|
||||||
|
GeneratePropertyAccessorsForType(prop, code, compilation, processedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
code.AppendLine("}");
|
||||||
|
|
||||||
|
//var code3 = $@"
|
||||||
|
// public sealed class {classSymbol.Name}Accessor : ISourceEntityAccessor<{classSymbol.Name}>
|
||||||
|
// {{
|
||||||
|
// public object GetPropertyValue({classSymbol.Name} entity, string propName) => propName switch
|
||||||
|
// {{
|
||||||
|
// {GeneratePropertyCases(classSymbol)}
|
||||||
|
// _ => throw new ArgumentException(""无效属性名"")
|
||||||
|
// }};
|
||||||
|
|
||||||
|
// {GenerateTupleSupport(classSymbol)}
|
||||||
|
// }}";
|
||||||
|
|
||||||
|
return code.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取泛型参数
|
/// 获取泛型参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -125,8 +240,65 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
|||||||
var parameters = symbol.TypeParameters.Select(t => t.Name);
|
var parameters = symbol.TypeParameters.Select(t => t.Name);
|
||||||
return $"<{string.Join(", ", parameters)}>";
|
return $"<{string.Join(", ", parameters)}>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成属性访问器代码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prop"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <param name="compilation"></param>
|
||||||
|
/// <param name="processedTypes"></param>
|
||||||
|
private static void GeneratePropertyAccessorsForType(
|
||||||
|
IPropertySymbol prop,
|
||||||
|
StringBuilder code,
|
||||||
|
Compilation compilation,
|
||||||
|
HashSet<ITypeSymbol> processedTypes)
|
||||||
|
{
|
||||||
|
// 安全类型转换
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理元组类型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prop"></param>
|
||||||
|
/// <param name="tupleType"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
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>
|
||||||
/// 生成标准属性的访问器
|
/// 生成标准属性的访问器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -143,330 +315,63 @@ namespace JiShe.CollectBus.IncrementalGenerator
|
|||||||
code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
|
code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建实体访问器代码(支持泛型)
|
/// 处理嵌套类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static string BuildAccessorsForSourceEntity(
|
/// <param name="typeSymbol"></param>
|
||||||
INamedTypeSymbol classSymbol,
|
/// <param name="compilation"></param>
|
||||||
Compilation compilation,
|
/// <param name="processedTypes"></param>
|
||||||
HashSet<ITypeSymbol> processedTypes)
|
private static void ProcessNestedType(ITypeSymbol typeSymbol, Compilation compilation, HashSet<ITypeSymbol> processedTypes)
|
||||||
{
|
{
|
||||||
var code = new StringBuilder();
|
if (typeSymbol is not INamedTypeSymbol namedType) return;
|
||||||
code.AppendLine("// <auto-generated/>");
|
if (!ShouldProcessNestedType(namedType)) return;
|
||||||
code.AppendLine("#nullable enable");
|
if (!processedTypes.Add(namedType)) return;
|
||||||
code.AppendLine("using System;");
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
//生成当前类属性访问
|
|
||||||
GetGeneratePropertyValueForSourceEntity(
|
|
||||||
propList,
|
|
||||||
code,
|
|
||||||
compilation,
|
|
||||||
classSymbol);
|
|
||||||
|
|
||||||
//生成当前类属性设置
|
|
||||||
SetGeneratePropertyValueForSourceEntity(
|
|
||||||
propList,
|
|
||||||
code,
|
|
||||||
compilation,
|
|
||||||
classSymbol);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
code.AppendLine("}");
|
|
||||||
return code.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生成泛型ValueTuple 元组访问器
|
/// 处理嵌套类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void GenerateTupleAccessors(
|
/// <param name="symbol"></param>
|
||||||
IPropertySymbol prop,
|
/// <returns></returns>
|
||||||
INamedTypeSymbol tupleType,
|
private static bool ShouldProcessNestedType(INamedTypeSymbol symbol)
|
||||||
StringBuilder code,
|
|
||||||
INamedTypeSymbol classSymbol)
|
|
||||||
{
|
{
|
||||||
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
return symbol.DeclaredAccessibility == Accessibility.Public &&
|
||||||
var tupleElements = tupleType.TupleElements;
|
!symbol.IsTupleType &&
|
||||||
|
!symbol.IsAnonymousType &&
|
||||||
for (int i = 0; i < tupleElements.Length; i++)
|
!symbol.IsImplicitlyDeclared &&
|
||||||
{
|
!symbol.Name.StartsWith("<");
|
||||||
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>
|
/// <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>
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
private static string BuildFactoryCode()
|
private static string BuildFactoryCode()
|
||||||
{
|
{
|
||||||
return """
|
return """
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Reflection;
|
namespace JiShe.CollectBus.Analyzers.Shared;
|
||||||
|
public static class SourceEntityAccessorFactory
|
||||||
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 =>
|
private static readonly ConcurrentDictionary<Type, object> _accessors = new();
|
||||||
|
|
||||||
|
public static ISourceEntityAccessor<T> GetAccessor<T>()
|
||||||
{
|
{
|
||||||
// 获取泛型类型定义信息(如果是泛型类型)
|
if (!_accessors.TryGetValue(typeof(T), out var accessor))
|
||||||
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());
|
accessor = Activator.CreateInstance(
|
||||||
|
Type.GetType($"{typeof(T).Namespace}.{typeof(T).Name}Accessor")!)!;
|
||||||
|
_accessors.TryAdd(typeof(T), accessor);
|
||||||
}
|
}
|
||||||
|
return (ISourceEntityAccessor<T>)accessor!;
|
||||||
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> PropertyList {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(" };");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -15,6 +15,6 @@ namespace JiShe.CollectBus.IoTDB.Model
|
|||||||
/// 单项数据键值对
|
/// 单项数据键值对
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SingleMeasuring(nameof(SingleColumn))]
|
[SingleMeasuring(nameof(SingleColumn))]
|
||||||
public required ValueTuple<string, T> SingleColumn { get; set; }
|
public required Tuple<string, T> SingleColumn { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,77 +0,0 @@
|
|||||||
// <auto-generated/>
|
|
||||||
#nullable enable
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using JiShe.CollectBus.Analyzers.Shared;
|
|
||||||
namespace JiShe.CollectBus.IoTDB.Model;
|
|
||||||
|
|
||||||
public sealed class TableModelSingleMeasuringEntityAccessor3<T> : ISourceEntityAccessor<global::JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T>>
|
|
||||||
{
|
|
||||||
public static string GetSingleColumn_Item1(global::JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T> obj) => obj.SingleColumn.Item1;
|
|
||||||
public static void SetSingleColumn_Item1(global::JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T> obj, string value) => obj.SingleColumn = (value, obj.SingleColumn.Item2);
|
|
||||||
public static T GetSingleColumn_Item2(global::JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T> obj) => obj.SingleColumn.Item2;
|
|
||||||
public static void SetSingleColumn_Item2(global::JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T> obj, T value) => obj.SingleColumn = (obj.SingleColumn.Item1, value);
|
|
||||||
public static string GetSystemName(JiShe.CollectBus.IoTDB.Model.IoTEntity obj) => obj.SystemName;
|
|
||||||
public static void SetSystemName(JiShe.CollectBus.IoTDB.Model.IoTEntity obj, string value) => obj.SystemName = value;
|
|
||||||
public static string GetProjectId(JiShe.CollectBus.IoTDB.Model.IoTEntity obj) => obj.ProjectId;
|
|
||||||
public static void SetProjectId(JiShe.CollectBus.IoTDB.Model.IoTEntity obj, string value) => obj.ProjectId = value;
|
|
||||||
public static string GetDeviceType(JiShe.CollectBus.IoTDB.Model.IoTEntity obj) => obj.DeviceType;
|
|
||||||
public static void SetDeviceType(JiShe.CollectBus.IoTDB.Model.IoTEntity obj, string value) => obj.DeviceType = value;
|
|
||||||
public static string GetDeviceId(JiShe.CollectBus.IoTDB.Model.IoTEntity obj) => obj.DeviceId;
|
|
||||||
public static void SetDeviceId(JiShe.CollectBus.IoTDB.Model.IoTEntity obj, string value) => obj.DeviceId = value;
|
|
||||||
public static long GetTimestamps(JiShe.CollectBus.IoTDB.Model.IoTEntity obj) => obj.Timestamps;
|
|
||||||
public static void SetTimestamps(JiShe.CollectBus.IoTDB.Model.IoTEntity obj, long value) => obj.Timestamps = value;
|
|
||||||
public List<string> PropertyList { get; } = new List<string>()
|
|
||||||
{
|
|
||||||
"SingleColumn.Item1","SingleColumn.Item2","SystemName","ProjectId","DeviceType","DeviceId","Timestamps" };
|
|
||||||
public object GetPropertyValue(JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T> targetEntity, string propertyName)
|
|
||||||
{
|
|
||||||
return propertyName switch
|
|
||||||
{
|
|
||||||
"SingleColumn.Item1" => GetSingleColumn_Item1(targetEntity),
|
|
||||||
"SingleColumn.Item2" => GetSingleColumn_Item2(targetEntity),
|
|
||||||
"SystemName" => GetSystemName(targetEntity),
|
|
||||||
"ProjectId" => GetProjectId(targetEntity),
|
|
||||||
"DeviceType" => GetDeviceType(targetEntity),
|
|
||||||
"DeviceId" => GetDeviceId(targetEntity),
|
|
||||||
"Timestamps" => GetTimestamps(targetEntity),
|
|
||||||
_ => throw new ArgumentException($"Unknown property: {propertyName}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public void SetPropertyValue(JiShe.CollectBus.IoTDB.Model.TableModelSingleMeasuringEntity<T> targetEntity, string propertyName, object value)
|
|
||||||
{
|
|
||||||
switch (propertyName)
|
|
||||||
{
|
|
||||||
case "SingleColumn.Item1":
|
|
||||||
SetSingleColumn_Item1(
|
|
||||||
targetEntity, (string)value);
|
|
||||||
break;
|
|
||||||
case "SingleColumn.Item2":
|
|
||||||
SetSingleColumn_Item2(
|
|
||||||
targetEntity, (T)value);
|
|
||||||
break;
|
|
||||||
case "SystemName":
|
|
||||||
SetSystemName(
|
|
||||||
targetEntity, (string)value);
|
|
||||||
break;
|
|
||||||
case "ProjectId":
|
|
||||||
SetProjectId(
|
|
||||||
targetEntity, (string)value);
|
|
||||||
break;
|
|
||||||
case "DeviceType":
|
|
||||||
SetDeviceType(
|
|
||||||
targetEntity, (string)value);
|
|
||||||
break;
|
|
||||||
case "DeviceId":
|
|
||||||
SetDeviceId(
|
|
||||||
targetEntity, (string)value);
|
|
||||||
break;
|
|
||||||
case "Timestamps":
|
|
||||||
SetTimestamps(
|
|
||||||
targetEntity, (long)value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentException($"Unknown property: {propertyName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,6 +15,6 @@ namespace JiShe.CollectBus.IoTDB.Model
|
|||||||
/// 单项数据键值对
|
/// 单项数据键值对
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SingleMeasuring(nameof(SingleMeasuring))]
|
[SingleMeasuring(nameof(SingleMeasuring))]
|
||||||
public required ValueTuple<string, T> SingleMeasuring { get; set; }
|
public required Tuple<string, T> SingleMeasuring { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ using JiShe.CollectBus.IoTDB.Options;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities;
|
using Volo.Abp.Domain.Entities;
|
||||||
using JiShe.CollectBus.Analyzers.Shared;
|
|
||||||
|
|
||||||
namespace JiShe.CollectBus.IoTDB.Provider
|
namespace JiShe.CollectBus.IoTDB.Provider
|
||||||
{
|
{
|
||||||
@ -177,8 +176,6 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<DeviceMetadata> GetMetadata<T>() where T : IoTEntity
|
public async Task<DeviceMetadata> GetMetadata<T>() where T : IoTEntity
|
||||||
{
|
{
|
||||||
var accessor = SourceEntityAccessorFactory.GetAccessor<T>();
|
|
||||||
|
|
||||||
var columns = CollectColumnMetadata(typeof(T));
|
var columns = CollectColumnMetadata(typeof(T));
|
||||||
var metadata = BuildDeviceMetadata<T>(columns);
|
var metadata = BuildDeviceMetadata<T>(columns);
|
||||||
var metaData = MetadataCache.AddOrUpdate(
|
var metaData = MetadataCache.AddOrUpdate(
|
||||||
@ -263,8 +260,6 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
|||||||
List<string> tempColumnNames = new List<string>();
|
List<string> tempColumnNames = new List<string>();
|
||||||
tempColumnNames.AddRange(metadata.ColumnNames);
|
tempColumnNames.AddRange(metadata.ColumnNames);
|
||||||
|
|
||||||
var accessor = SourceEntityAccessorFactory.GetAccessor<T>();
|
|
||||||
|
|
||||||
var entityTypeAttribute = typeof(T).GetCustomAttribute<EntityTypeAttribute>();
|
var entityTypeAttribute = typeof(T).GetCustomAttribute<EntityTypeAttribute>();
|
||||||
|
|
||||||
if (entityTypeAttribute == null)
|
if (entityTypeAttribute == null)
|
||||||
@ -300,74 +295,69 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
|||||||
|
|
||||||
foreach (var measurement in tempColumnNames)
|
foreach (var measurement in tempColumnNames)
|
||||||
{
|
{
|
||||||
rowValues.Add(accessor.GetPropertyValue(entity,measurement));
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//foreach (var measurement in tempColumnNames)
|
values.Add(rowValues);
|
||||||
//{
|
|
||||||
|
|
||||||
// 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))
|
if (!string.IsNullOrWhiteSpace(tableNameOrTreePath))
|
||||||
@ -566,8 +556,6 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
|||||||
//metadata.ColumnNames.Insert(0, "Timestamps");
|
//metadata.ColumnNames.Insert(0, "Timestamps");
|
||||||
//metadata.DataTypes.Insert(0, TSDataType.TIMESTAMP);
|
//metadata.DataTypes.Insert(0, TSDataType.TIMESTAMP);
|
||||||
|
|
||||||
var accessor = SourceEntityAccessorFactory.GetAccessor<T>();
|
|
||||||
|
|
||||||
while (dataSet.HasNext() && results.Count < pageSize)
|
while (dataSet.HasNext() && results.Count < pageSize)
|
||||||
{
|
{
|
||||||
var record = dataSet.Next();
|
var record = dataSet.Next();
|
||||||
@ -590,14 +578,11 @@ namespace JiShe.CollectBus.IoTDB.Provider
|
|||||||
|
|
||||||
if (measurement.ToLower().EndsWith("time"))
|
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
|
else
|
||||||
{
|
{
|
||||||
accessor.SetPropertyValue(entity, measurement, tempValue);
|
typeof(T).GetProperty(measurement)?.SetValue(entity, tempValue);
|
||||||
//typeof(T).GetProperty(measurement)?.SetValue(entity, tempValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -90,7 +90,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
|||||||
DeviceType = $"{data.MeterType}",
|
DeviceType = $"{data.MeterType}",
|
||||||
ProjectId = $"{data.ProjectId}",
|
ProjectId = $"{data.ProjectId}",
|
||||||
Timestamps = data.TimeSpan!.Value.GetFormatTime(analysisBaseDto.DensityUnit, analysisBaseDto.TimeDensity).GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
Timestamps = data.TimeSpan!.Value.GetFormatTime(analysisBaseDto.DensityUnit, analysisBaseDto.TimeDensity).GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||||
SingleMeasuring = (data.FiledName ?? string.Empty, data.DataValue ?? default)
|
SingleMeasuring = new Tuple<string, T>(data.FiledName ?? string.Empty, data.DataValue ?? default)
|
||||||
};
|
};
|
||||||
_runtimeContext.UseTableSessionPool = true; // 使用表模型池
|
_runtimeContext.UseTableSessionPool = true; // 使用表模型池
|
||||||
var taskSendInfo = await _dbProvider.QueryAsync<MeterReadingTelemetryPacketInfo>(new IoTDBQueryOptions() { TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(), Conditions = conditions, PageIndex = 0, PageSize = 1 });
|
var taskSendInfo = await _dbProvider.QueryAsync<MeterReadingTelemetryPacketInfo>(new IoTDBQueryOptions() { TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(), Conditions = conditions, PageIndex = 0, PageSize = 1 });
|
||||||
@ -193,7 +193,7 @@ namespace JiShe.CollectBus.Protocol.T37612012.AnalysisData
|
|||||||
DeviceType = $"{item.MeterType}",
|
DeviceType = $"{item.MeterType}",
|
||||||
ProjectId = $"{item.ProjectId}",
|
ProjectId = $"{item.ProjectId}",
|
||||||
Timestamps = item.TimeSpan!.Value.GetFormatTime(analysisBaseDto.DensityUnit, analysisBaseDto.TimeDensity).GetDateTimeOffset().ToUnixTimeMilliseconds(), // TODO:这里暂时格式化15分钟数据,需要进行调整
|
Timestamps = item.TimeSpan!.Value.GetFormatTime(analysisBaseDto.DensityUnit, analysisBaseDto.TimeDensity).GetDateTimeOffset().ToUnixTimeMilliseconds(), // TODO:这里暂时格式化15分钟数据,需要进行调整
|
||||||
SingleMeasuring = (item.FiledName ?? string.Empty, item.DataValue ?? default)
|
SingleMeasuring = new Tuple<string, T>(item.FiledName ?? string.Empty, item.DataValue ?? default)
|
||||||
};
|
};
|
||||||
_runtimeContext.UseTableSessionPool = true; // 使用表模型池
|
_runtimeContext.UseTableSessionPool = true; // 使用表模型池
|
||||||
var taskSendInfo = await _dbProvider.QueryAsync<MeterReadingTelemetryPacketInfo>(new IoTDBQueryOptions() { TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(), Conditions = conditions, PageIndex = 0, PageSize = 1 });
|
var taskSendInfo = await _dbProvider.QueryAsync<MeterReadingTelemetryPacketInfo>(new IoTDBQueryOptions() { TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(), Conditions = conditions, PageIndex = 0, PageSize = 1 });
|
||||||
|
|||||||
@ -72,10 +72,6 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
};
|
};
|
||||||
//ElectricityMeterTreeModelExtension.GetCurrent()
|
//ElectricityMeterTreeModelExtension.GetCurrent()
|
||||||
//SourceEntityAccessorFactory.SetCurrent(meter);
|
//SourceEntityAccessorFactory.SetCurrent(meter);
|
||||||
|
|
||||||
//ElectricityMeterTreeModelAccessor.
|
|
||||||
//TableModelSingleMeasuringEntityExtension
|
|
||||||
//TableModelSingleMeasuringEntityAccessor.GetSystemName(meter);
|
|
||||||
await _iotDBProvider.InsertAsync(meter);
|
await _iotDBProvider.InsertAsync(meter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,8 +170,6 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task TestTreeModelSingleMeasuringEntity(string measuring, string value, DateTime time)
|
public async Task TestTreeModelSingleMeasuringEntity(string measuring, string value, DateTime time)
|
||||||
{
|
{
|
||||||
time = DateTime.Now;
|
|
||||||
|
|
||||||
var meter = new TreeModelSingleMeasuringEntity<string>()
|
var meter = new TreeModelSingleMeasuringEntity<string>()
|
||||||
{
|
{
|
||||||
SystemName = "energy",
|
SystemName = "energy",
|
||||||
@ -183,7 +177,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
DeviceType = "1",
|
DeviceType = "1",
|
||||||
ProjectId = "10059",
|
ProjectId = "10059",
|
||||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||||
SingleMeasuring = (measuring, value)
|
SingleMeasuring = new Tuple<string, string>(measuring, value)
|
||||||
};
|
};
|
||||||
await _iotDBProvider.InsertAsync(meter);
|
await _iotDBProvider.InsertAsync(meter);
|
||||||
}
|
}
|
||||||
@ -196,7 +190,6 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task TestTreeModelSingleMeasuringEntity2(string measuring, int value, DateTime time)
|
public async Task TestTreeModelSingleMeasuringEntity2(string measuring, int value, DateTime time)
|
||||||
{
|
{
|
||||||
time = DateTime.Now;
|
|
||||||
var meter = new TreeModelSingleMeasuringEntity<int>()
|
var meter = new TreeModelSingleMeasuringEntity<int>()
|
||||||
{
|
{
|
||||||
SystemName = "energy",
|
SystemName = "energy",
|
||||||
@ -204,7 +197,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
DeviceType = "Ammeter",
|
DeviceType = "Ammeter",
|
||||||
ProjectId = "10059",
|
ProjectId = "10059",
|
||||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||||
SingleMeasuring = (measuring, value)
|
SingleMeasuring = new Tuple<string, int>(measuring, value)
|
||||||
};
|
};
|
||||||
await _iotDBProvider.InsertAsync(meter);
|
await _iotDBProvider.InsertAsync(meter);
|
||||||
}
|
}
|
||||||
@ -217,8 +210,6 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task TestTableModelSingleMeasuringEntity(string measuring, string value, DateTime time)
|
public async Task TestTableModelSingleMeasuringEntity(string measuring, string value, DateTime time)
|
||||||
{
|
{
|
||||||
time = DateTime.Now;
|
|
||||||
|
|
||||||
var meter = new TableModelSingleMeasuringEntity<string>()
|
var meter = new TableModelSingleMeasuringEntity<string>()
|
||||||
{
|
{
|
||||||
SystemName = "energy",
|
SystemName = "energy",
|
||||||
@ -226,7 +217,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
DeviceType = "Ammeter",
|
DeviceType = "Ammeter",
|
||||||
ProjectId = "10059",
|
ProjectId = "10059",
|
||||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||||
SingleColumn = (measuring, value)
|
SingleColumn = new Tuple<string, string>(measuring, value)
|
||||||
};
|
};
|
||||||
_dbContext.UseTableSessionPool = true;
|
_dbContext.UseTableSessionPool = true;
|
||||||
await _iotDBProvider.InsertAsync(meter);
|
await _iotDBProvider.InsertAsync(meter);
|
||||||
@ -240,8 +231,6 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task TestTableModelSingleMeasuringEntity2(string measuring, int value, DateTime time)
|
public async Task TestTableModelSingleMeasuringEntity2(string measuring, int value, DateTime time)
|
||||||
{
|
{
|
||||||
time = DateTime.Now;
|
|
||||||
|
|
||||||
var meter = new TableModelSingleMeasuringEntity<int>()
|
var meter = new TableModelSingleMeasuringEntity<int>()
|
||||||
{
|
{
|
||||||
SystemName = "energy",
|
SystemName = "energy",
|
||||||
@ -249,7 +238,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
|
|||||||
DeviceType = "Ammeter",
|
DeviceType = "Ammeter",
|
||||||
ProjectId = "10059",
|
ProjectId = "10059",
|
||||||
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
Timestamps = time.GetDateTimeOffset().ToUnixTimeMilliseconds(),
|
||||||
SingleColumn = (measuring, value)
|
SingleColumn = new Tuple<string, int>(measuring, value)
|
||||||
};
|
};
|
||||||
_dbContext.UseTableSessionPool = true;
|
_dbContext.UseTableSessionPool = true;
|
||||||
await _iotDBProvider.InsertAsync(meter);
|
await _iotDBProvider.InsertAsync(meter);
|
||||||
|
|||||||
@ -336,47 +336,47 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
|
|
||||||
//此处代码不要删除
|
//此处代码不要删除
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//var timeDensity = "15";
|
var timeDensity = "15";
|
||||||
//var serverTagName = "JiSheCollectBus2";
|
var serverTagName = "JiSheCollectBus2";
|
||||||
//var redisCacheMeterInfoHashKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoHashKey, SystemType, serverTagName, MeterTypeEnum.Ammeter, timeDensity)}";
|
var redisCacheMeterInfoHashKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoHashKey, SystemType, serverTagName, MeterTypeEnum.Ammeter, timeDensity)}";
|
||||||
//var redisCacheMeterInfoSetIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoSetIndexKey, SystemType, serverTagName, MeterTypeEnum.Ammeter, timeDensity)}";
|
var redisCacheMeterInfoSetIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoSetIndexKey, SystemType, serverTagName, MeterTypeEnum.Ammeter, timeDensity)}";
|
||||||
//var redisCacheMeterInfoZSetScoresIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoZSetScoresIndexKey, SystemType, serverTagName, MeterTypeEnum.Ammeter, timeDensity)}";
|
var redisCacheMeterInfoZSetScoresIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoZSetScoresIndexKey, SystemType, serverTagName, MeterTypeEnum.Ammeter, timeDensity)}";
|
||||||
|
|
||||||
List<AmmeterInfo> meterInfos = new List<AmmeterInfo>();
|
List<AmmeterInfo> meterInfos = new List<AmmeterInfo>();
|
||||||
//List<string> focusAddressDataLista = new List<string>();
|
List<string> focusAddressDataLista = new List<string>();
|
||||||
//var timer1 = Stopwatch.StartNew();
|
var timer1 = Stopwatch.StartNew();
|
||||||
|
|
||||||
//var allIds = new HashSet<string>();
|
var allIds = new HashSet<string>();
|
||||||
//decimal? score = null;
|
decimal? score = null;
|
||||||
//string member = null;
|
string member = null;
|
||||||
|
|
||||||
//while (true)
|
while (true)
|
||||||
//{
|
{
|
||||||
// var page = await _redisDataCacheService.GetAllPagedData<AmmeterInfo>(
|
var page = await _redisDataCacheService.GetAllPagedData<AmmeterInfo>(
|
||||||
// redisCacheMeterInfoHashKeyTemp,
|
redisCacheMeterInfoHashKeyTemp,
|
||||||
// redisCacheMeterInfoZSetScoresIndexKeyTemp,
|
redisCacheMeterInfoZSetScoresIndexKeyTemp,
|
||||||
// pageSize: 1000,
|
pageSize: 1000,
|
||||||
// lastScore: score,
|
lastScore: score,
|
||||||
// lastMember: member);
|
lastMember: member);
|
||||||
|
|
||||||
// meterInfos.AddRange(page.Items);
|
meterInfos.AddRange(page.Items);
|
||||||
// focusAddressDataLista.AddRange(page.Items.Select(d => $"{d.MeterId}"));
|
focusAddressDataLista.AddRange(page.Items.Select(d => $"{d.MeterId}"));
|
||||||
// foreach (var item in page.Items)
|
foreach (var item in page.Items)
|
||||||
// {
|
{
|
||||||
// if (!allIds.Add(item.MemberId))
|
if (!allIds.Add(item.MemberId))
|
||||||
// {
|
{
|
||||||
// _logger.LogError($"{item.MemberId}Duplicate data found!");
|
_logger.LogError($"{item.MemberId}Duplicate data found!");
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// if (!page.HasNext) break;
|
if (!page.HasNext) break;
|
||||||
// score = page.NextScore;
|
score = page.NextScore;
|
||||||
// member = page.NextMember;
|
member = page.NextMember;
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
|
||||||
//timer1.Stop();
|
timer1.Stop();
|
||||||
//_logger.LogError($"电表初始化读取数据总共花费时间{timer1.ElapsedMilliseconds}毫秒");
|
_logger.LogError($"电表初始化读取数据总共花费时间{timer1.ElapsedMilliseconds}毫秒");
|
||||||
//DeviceGroupBalanceControl.InitializeCache(focusAddressDataLista, _kafkaOptions.NumPartitions);
|
DeviceGroupBalanceControl.InitializeCache(focusAddressDataLista, _kafkaOptions.NumPartitions);
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
var meterInfos = await GetAmmeterInfoList(gatherCode);
|
var meterInfos = await GetAmmeterInfoList(gatherCode);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ using JiShe.CollectBus.IoTDB.Model;
|
|||||||
namespace JiShe.CollectBus.Ammeters
|
namespace JiShe.CollectBus.Ammeters
|
||||||
{
|
{
|
||||||
[EntityType(EntityTypeEnum.TableModel)]
|
[EntityType(EntityTypeEnum.TableModel)]
|
||||||
//[SourceAnalyzers]
|
[SourceAnalyzers]
|
||||||
public class ElectricityMeter : IoTEntity
|
public class ElectricityMeter : IoTEntity
|
||||||
{
|
{
|
||||||
[ATTRIBUTEColumn]
|
[ATTRIBUTEColumn]
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using JiShe.CollectBus.IoTDB.Attribute;
|
using JiShe.CollectBus.IoTDB.Attribute;
|
||||||
using JiShe.CollectBus.IoTDB.Enums;
|
using JiShe.CollectBus.IoTDB.Enums;
|
||||||
using JiShe.CollectBus.IoTDB.Model;
|
using JiShe.CollectBus.IoTDB.Model;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Ammeters
|
namespace JiShe.CollectBus.Ammeters
|
||||||
{
|
{
|
||||||
@ -36,7 +35,5 @@ namespace JiShe.CollectBus.Ammeters
|
|||||||
|
|
||||||
[FIELDColumn]
|
[FIELDColumn]
|
||||||
public double? Currentd { get; set; }
|
public double? Currentd { get; set; }
|
||||||
|
|
||||||
public Tuple<int,string> TupleData { get; set;}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,8 +23,18 @@ namespace JiShe.CollectBus.Analyzers.Shared
|
|||||||
void SetPropertyValue(T entity, string propertyName, object value);
|
void SetPropertyValue(T entity, string propertyName, object value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 属性名称集合
|
/// 判断是否是元组属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
List<string> PropertyList { get; }
|
/// <param name="propertyName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IsTupleProperty(string propertyName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取元组属性值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity"></param>
|
||||||
|
/// <param name="tuplePropertyName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
(object Item1, object Item2) GetTupleParts(T entity, string tuplePropertyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user