OpenRobot.Framework.DynamicGeneralService 1.1.1

dotnet add package OpenRobot.Framework.DynamicGeneralService --version 1.1.1
                    
NuGet\Install-Package OpenRobot.Framework.DynamicGeneralService -Version 1.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OpenRobot.Framework.DynamicGeneralService" Version="1.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OpenRobot.Framework.DynamicGeneralService" Version="1.1.1" />
                    
Directory.Packages.props
<PackageReference Include="OpenRobot.Framework.DynamicGeneralService" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OpenRobot.Framework.DynamicGeneralService --version 1.1.1
                    
#r "nuget: OpenRobot.Framework.DynamicGeneralService, 1.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OpenRobot.Framework.DynamicGeneralService@1.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OpenRobot.Framework.DynamicGeneralService&version=1.1.1
                    
Install as a Cake Addin
#tool nuget:?package=OpenRobot.Framework.DynamicGeneralService&version=1.1.1
                    
Install as a Cake Tool

OpenRobot.Framework.DynamicGeneralService

NuGet .NET

一个强大的 .NET 8.0 动态属性管理服务库,为处理动态属性场景(如设备配置、结构化参数等)提供一站式解决方案。该库与 OpenRobot.Framework.DynamicModel 紧密配合,实现了动态属性的 CRUD 操作、实体与 DTO 之间的双向转换、以及嵌套属性树管理。

主要特性

  • 动态属性管理 - 支持运行时动态创建和管理属性结构
  • 嵌套属性支持 - 完整支持点号分隔的嵌套属性路径(如 "Structure.Servos.Axis1.Name")
  • 数组节点管理 - 内置数组属性的创建、删除和索引管理
  • 双向转换 - 实体与 DTO 之间的无缝转换
  • 批量更新 - 高效的批量属性值更新
  • ABP 框架集成 - 基于 ABP 框架的仓储模式,支持依赖注入

安装

dotnet add package OpenRobot.Framework.DynamicGeneralService

或在 Visual Studio 的 NuGet 包管理器控制台中运行:

Install-Package OpenRobot.Framework.DynamicGeneralService

快速开始

1. 定义动态属性实体

using Abp.Domain.Entities;
using OpenRobot.Framework.DynamicModel;

public class MyPropEntity : Entity, IDynamicPropEntity
{
    public int DynamicPropertyId { get; set; }
    public string PropertyName { get; set; }
    public string TypeName { get; set; }
    public string AttrName { get; set; }
    public bool IsBaseType { get; set; }
    public bool IsArray { get; set; }
    public int Index { get; set; }
    public string Value { get; set; }
    public string ParentID { get; set; }
    public string Title { get; set; }
    public string Regex { get; set; }
    public string ErrorMessage { get; set; }
    public DateTime LastUpdateTime { get; set; }
}

2. 创建服务实例

using OpenRobot.Framework.DynamicGeneralService;

public class MyApplicationService : ITransientDependency
{
    private readonly GeneralPropService<MyPropEntity, int> _generalPropService;
    private readonly IRepository<MyPropEntity, int> _repository;

    public MyApplicationService(IRepository<MyPropEntity, int> repository)
    {
        _repository = repository;
        _generalPropService = new GeneralPropService<MyPropEntity, int>(repository);
    }
}

使用示例

创建嵌套数组属性

// 定义模板 DTO
public class ServoAxisTemplate : IDynamicTemplateDto
{
    [Description("轴名称")]
    public string Name { get; set; }

    [Description("最大速度")]
    public int MaxSpeed { get; set; }

    [Description("使能状态")]
    public bool Enabled { get; set; }
}

// 创建多个伺服轴配置
var createServoDto = new CreateServoAxisDto
{
    DeviceTypeId = 123,
    Items = new List<ServoAxisTemplate>
    {
        new ServoAxisTemplate { Name = "X轴", MaxSpeed = 1000, Enabled = true },
        new ServoAxisTemplate { Name = "Y轴", MaxSpeed = 800, Enabled = true },
        new ServoAxisTemplate { Name = "Z轴", MaxSpeed = 500, Enabled = false }
    }
};

// 构建动态属性实体列表
var propEntities = await _generalPropService.GetBuildPropList(
    "Structure.Servos",           // 父属性标签
    createServoDto.DeviceTypeId,  // 父实体 ID
    () => createServoDto.Items    // DTO 列表提供函数
);

// 批量插入到数据库
await _repository.InsertManyAsync(propEntities);

批量更新属性值

var updateDto = new GeneralPropUpdateDto
{
    Items = new List<UpdatePropItemDto>
    {
        new UpdatePropItemDto { Id = 1, PropName = "Name", PropValue = "新名称" },
        new UpdatePropItemDto { Id = 2, PropName = "MaxSpeed", PropValue = "1200" },
        new UpdatePropItemDto { Id = 3, PropName = "Enabled", PropValue = "false" }
    }
};

await _generalPropService.UpdateAsync(updateDto);

删除数组节点

// 删除指定叶子节点及其所有子属性
// 例如:删除 "Y轴" 及其所有子属性
await _generalPropService.DeleteArrayNodeByLeafId(leafId: 456);

查询并转换为 DTO

// 定义结果 DTO
public class ServoConfigDto : ICustomPropConvert
{
    public string Name { get; set; }
    public int MaxSpeed { get; set; }
    public bool Enabled { get; set; }

    public void OpenDynamicPropertryBuild(List<OpenModel> openModels)
    {
        foreach (var model in openModels)
        {
            switch (model.PropertyName)
            {
                case "Name":
                    Name = model.Value;
                    break;
                case "MaxSpeed":
                    MaxSpeed = int.Parse(model.Value);
                    break;
                case "Enabled":
                    Enabled = bool.Parse(model.Value);
                    break;
            }
        }
    }
}

// 方式一:从数据库查询并转换单个 DTO
var dto = await _generalPropService.ConvertToSingleDto<ServoConfigDto>(
    x => x.DynamicPropertyId == 123 && x.PropertyName.StartsWith("Structure.Servos")
);

// 方式二:从已有实体列表转换
var dto = _generalPropService.ConvertToSingleDto<ServoConfigDto>(propList);

查询并转换为 DTO 列表

var mainIds = new List<int> { 123, 124, 125 };

var dtoList = await _generalPropService.ConvertToListDto<ServoConfigDto>(
    x => mainIds.Contains(x.DynamicPropertyId),
    mainIds
);

实体与 OpenModel 之间的转换

// 实体列表转 OpenModel 列表
var openModels = _generalPropService.ListEntityToListOpenModel(entityList);

// OpenModel 列表转实体列表
var entities = _generalPropService.ListOpenModelToListEntity(openModels);

完整示例:设备配置管理

using Abp.Domain.Repositories;
using Abp.Dependency;
using OpenRobot.Framework.DynamicGeneralService;
using OpenRobot.Framework.DynamicModel;
using Abp.UI;

public class DeviceConfigService : ITransientDependency
{
    private readonly IRepository<DeviceConfigPropEntity, int> _repository;
    private readonly GeneralPropService<DeviceConfigPropEntity, int> _generalPropService;

    public DeviceConfigService(
        IRepository<DeviceConfigPropEntity, int> repository)
    {
        _repository = repository;
        _generalPropService = new GeneralPropService<DeviceConfigPropEntity, int>(repository);
    }

    /// <summary>
    /// 创建伺服轴配置
    /// </summary>
    public async Task CreateServoAxis(CreateServoAxisDto createServo)
    {
        var propEntities = await _generalPropService.GetBuildPropList(
            "Structure.Servos",
            createServo.DeviceTypeId,
            () => createServo.Items
        );

        if (propEntities.Count == 0)
        {
            throw new UserFriendlyException("操作成功,未创建有效数据!");
        }

        await _repository.InsertManyAsync(propEntities);
    }

    /// <summary>
    /// 创建主轴配置
    /// </summary>
    public async Task CreateSpindleAxis(CreateSpindleAxisDto createSpindle)
    {
        var propEntities = await _generalPropService.GetBuildPropList(
            "Structure.Spindles",
            createSpindle.DeviceTypeId,
            () => createSpindle.Items
        );

        if (propEntities.Count == 0)
        {
            throw new UserFriendlyException("操作成功,未创建有效数据!");
        }

        await _repository.InsertManyAsync(propEntities);
    }

    /// <summary>
    /// 获取设备结构配置
    /// </summary>
    public async Task<StructureConfigDto> GetStructureConfig(int deviceId)
    {
        var queryable = await _repository.GetQueryableAsync();
        var propList = await queryable
            .AsNoTracking()
            .Where(d => d.DynamicPropertyId == deviceId &&
                       d.PropertyName.StartsWith("Structure."))
            .ToListAsync();

        if (propList.Count == 0)
        {
            throw new UserFriendlyException("未找到符合条件的数据,请检查数据是否正确");
        }

        // 移除属性名前缀,简化后续处理
        propList.ForEach(d =>
        {
            d.PropertyName = d.PropertyName.Replace("Structure.", "");
        });

        return _generalPropService.ConvertToSingleDto<StructureConfigDto>(propList);
    }

    /// <summary>
    /// 删除轴配置
    /// </summary>
    public async Task DeleteAxis(int leafId)
    {
        await _generalPropService.DeleteArrayNodeByLeafId(leafId);
    }

    /// <summary>
    /// 批量更新配置
    /// </summary>
    public async Task BatchUpdate(GeneralPropUpdateDto updateDto)
    {
        await _generalPropService.UpdateAsync(updateDto);
    }
}

API 参考

GeneralPropService<TEntity, TPrimaryKey>

泛型服务类,提供动态属性的完整管理功能。

类型参数
  • TEntity : Entity, IDynamicPropEntity, IEntity<TPrimaryKey>
    • 动态属性实体类型,必须继承自 ABP 的 Entity 并实现 IDynamicPropEntity
  • TPrimaryKey : 主键类型(通常是 int 或 long)
构造函数
public GeneralPropService(IRepository<TEntity, TPrimaryKey> repository)
主要方法
方法 说明 返回类型
UpdateAsync 批量更新属性值 Task
GetBuildPropList 从 DTO 列表构建动态属性实体 Task<List<TEntity>>
DeleteArrayNodeByLeafId 通过叶子节点 ID 删除整个数组节点 Task
ConvertToSingleDto 将属性实体转换为单个 DTO Task<T>
ConvertToListDto 将属性实体转换为 DTO 列表 Task<List<T>>
ListEntityToListOpenModel 实体列表转 OpenModel 列表 List<OpenModel>
ListOpenModelToListEntity OpenModel 列表转实体列表 List<TEntity>

数据模型

⚠️ 1.1.0 变更GeneralPropUpdateDtoUpdatePropItemDto 已迁移至 OpenRobot.Framework.DynamicModel 命名空间,请使用 using OpenRobot.Framework.DynamicModel; 导入。

GeneralPropUpdateDto

批量更新 DTO

// 命名空间:OpenRobot.Framework.DynamicModel
public class GeneralPropUpdateDto
{
    public List<UpdatePropItemDto> Items { get; set; }
    public int DynamicPropertyId { get; set; }
}
UpdatePropItemDto

单个更新项 DTO

// 命名空间:OpenRobot.Framework.DynamicModel
public class UpdatePropItemDto
{
    public int Id { get; set; }           // 属性记录 ID
    public string PropName { get; set; }  // 属性名称
    public string PropValue { get; set; } // 新属性值
}

属性命名约定

  • 点号分隔:嵌套属性使用点号分隔,如 Structure.Servos.Axis1.Name
  • 数组索引:数组属性通过 Index 字段分组,相同 Index 的属性属于同一数组元素
  • ParentID 格式:十六进制索引链,如 #00,#01,#02 表示路径层级

验证元数据

通过 OpenModel 可以携带验证信息:

  • Title:属性显示名称(来自 DescriptionAttribute
  • Regex:正则表达式(来自 RegularExpressionAttribute
  • ErrorMessage:验证错误消息

依赖项

包名 版本 用途
Abp 9.4.2 ASP.NET Boilerplate 框架
Abp.EntityFrameworkCore 9.4.2 EF Core 集成
OpenRobot.Framework.DynamicModel 最新 动态模型核心库

系统要求

  • .NET 8.0 或更高版本

扩展阅读

  • OpenRobot.Framework.DynamicModel - 动态模型核心库文档
  • Test/StructureService.md - 完整的设备配置管理示例

许可证

本项目采用 MIT 许可证。

作者

OpenRobot

反馈与贡献

欢迎通过以下方式提供反馈:

  • 提交 Issue
  • 发起 Pull Request
  • 联系维护者

版本历史

1.1.1 (2026-06-24)

  • 数据构建ParentID 修复:修复数据对象构建 ParentID 少了一个层级导致的 读取失败

1.1.0 (2026-06-23)

  • 数据模型迁移GeneralPropUpdateDtoUpdatePropItemDto 迁移至 OpenRobot.Framework.DynamicModel 核心库,不再依赖本项目的 Dto 命名空间
  • 更新 GeneralPropService 引用,使用 OpenRobot.Framework.DynamicModel 下的数据类型
  • 注意:如果之前从 OpenRobot.Framework.DynamicGeneralService.Dto 引用这些类型,请改为引用 OpenRobot.Framework.DynamicModel 命名空间
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 118 6/25/2026
1.1.0 107 6/23/2026
1.0.0 118 4/17/2026