以下是为 `Product` 实体添加扩展属性并触发分布式事件的详细实现,基于 ABP Framework 和你提供的 `WMSManagementDomainModule` 代码上下文。我将提供完整的代码示例,包括扩展属性的定义、分布式事件的配置以及事件处理逻辑,并确保代码清晰且符合 ABP 的最佳实践。
目标
1. 为 `Product` 实体添加一个扩展属性,例如 `BatchNumber`(批次号,字符串类型)。
2. 配置分布式事件,当 `Product` 实体创建或更新时,自动触发事件。
3. 实现事件处理器,处理 `Product` 变化事件(例如,记录日志或通知其他服务)。
代码实现
以下是更新后的 `WMSManagementDomainModule` 代码,以及相关的辅助类和事件处理器。为了便于理解,我将代码分为几个部分,并用注释说明每个部分的作用。
```xcsharp
using Volo.Abp;
using Volo.Abp.AutoMapper;
using Volo.Abp.Data;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.EventBus.Distributed;
namespace WMSManagement.Domain
{
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpDataProtectionModule),
typeof(WMSManagementDomainSharedModule))]
public class WMSManagementDomainModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new();
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 配置 AutoMapper
context.Services.AddAutoMapperObjectMapper<WMSManagementDomainModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<WMSManagementDomainMapperProfile>(validate: true);
});
// 配置分布式事件:为 Product 实体启用自动事件触发
Configure<AbpDistributedEntityEventOptions>(options =>
{
options.AutoEventSelectors.Add<Product>(); // 当 Product 实体变化时触发事件
});
}
public override void PostConfigureServices(ServiceConfigurationContext context)
{
OneTimeRunner.Run(() =>
{
// 为 Product 实体添加扩展属性:BatchNumber
ObjectExtensionManager.Instance
.AddOrUpdateProperty<Product, string>(
propertyName: "BatchNumber",
configuration =>
{
configuration.DefaultValue = ""; // 默认值为空字符串
configuration.CheckPairDefinitionOnMapping = true; // 确保映射时验证
});
// 应用实体扩展配置
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity(
WMSManagementModuleExtensionConsts.ModuleName,
WMSManagementModuleExtensionConsts.EntityNames.Product,
typeof(Product)
);
});
}
}
}
```
辅助代码
以下是实现中涉及的其他类和配置文件,确保扩展属性和分布式事件能够正常工作。
1. Product 实体
假设 `Product` 是一个简单的实体,实现了 `IHasExtraProperties` 接口以支持扩展属性。
```xcsharp
using Volo.Abp.Domain.Entities;
using Volo.Abp.Data;
namespace WMSManagement.Domain
{
public class Product : AggregateRoot<Guid>, IHasExtraProperties
{
public string Name { get; set; }
public decimal Price { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; } // 支持扩展属性
public Product()
{
ExtraProperties = new ExtraPropertyDictionary();
}
}
}
```
说明:
`Product` 继承 `AggregateRoot<Guid>`,表示它是一个聚合根,带有 `Guid` 类型的主键。
实现 `IHasExtraProperties`,提供 `ExtraProperties` 字典存储扩展属性(如 `BatchNumber`)。
构造函数初始化 `ExtraProperties`。
2. 模块扩展常量
定义模块名称和实体名称的常量,用于实体扩展配置。
```xcsharp
namespace WMSManagement.Domain
{
public static class WMSManagementModuleExtensionConsts
{
public const string ModuleName = "WMSManagement";
public static class EntityNames
{
public const string Product = "Product";
}
}
}
```
说明:
`ModuleName`:模块的唯一标识。
`EntityNames.Product`:`Product` 实体的逻辑名称,用于扩展配置。
3. AutoMapper 配置文件
为 `Product` 和其 DTO 配置映射,确保扩展属性(如 `BatchNumber`)也能正确映射。
```xcsharp
using AutoMapper;
using Volo.Abp.AutoMapper;
namespace WMSManagement.Domain
{
public class WMSManagementDomainMapperProfile : Profile
{
public WMSManagementDomainMapperProfile()
{
CreateMap<Product, ProductDto>()
.MapExtraProperties(); // 自动映射扩展属性(如 BatchNumber)
}
}
}
```
说明:
使用 `MapExtraProperties()` 确保 `ExtraProperties` 中的扩展属性(如 `BatchNumber`)被映射到 DTO。
`ProductDto` 是假设的 DTO 类,可能如下定义:
```csharp
public class ProductDto
{
public Guid Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string BatchNumber { get; set; } // 扩展属性
}
```
4. 分布式事件处理器
实现一个事件处理器,处理 `Product` 实体的创建或更新事件。
```xcsharp
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Data;
namespace WMSManagement.Domain
{
public class ProductEventHandler :
IDistributedEventHandler<EntityCreatedEto<Product>>,
IDistributedEventHandler<EntityUpdatedEto<Product>>,
ITransientDependency
{
public async Task HandleEventAsync(EntityCreatedEto<Product> eventData)
{
var product = eventData.Entity;
var batchNumber = product.GetProperty<string>("BatchNumber");
// 示例:记录日志或通知其他服务
Console.WriteLine($"Product created: {product.Name}, BatchNumber: {batchNumber}");
await Task.CompletedTask;
}
public async Task HandleEventAsync(EntityUpdatedEto<Product> eventData)
{
var product = eventData.Entity;
var batchNumber = product.GetProperty<string>("BatchNumber");
// 示例:记录日志或通知其他服务
Console.WriteLine($"Product updated: {product.Name}, BatchNumber: {batchNumber}");
await Task.CompletedTask;
}
}
}
```
说明:
实现 `IDistributedEventHandler` 接口,处理 `EntityCreatedEto<Product>` 和 `EntityUpdatedEto<Product>` 事件。
使用 `GetProperty<string>("BatchNumber")` 访问扩展属性。
目前仅打印日志,实际场景中可以调用其他服务(如更新库存、发送通知)。
`ITransientDependency` 表示该处理器是瞬时生命周期,适合事件处理。
代码功能说明
1. 扩展属性 (`BatchNumber`):
在 `PostConfigureServices` 中,通过 `ObjectExtensionManager` 为 `Product` 实体添加 `BatchNumber` 属性。
使用 `ModuleExtensionConfigurationHelper` 应用扩展配置,确保属性在 UI、API 和数据库中可用。
`BatchNumber` 存储在 `ExtraProperties` 字典中,数据库中通常以 JSON 格式保存。
2. 分布式事件:
在 `ConfigureServices` 中,配置 `AbpDistributedEntityEventOptions`,为 `Product` 实体启用自动事件触发。
当 `Product` 实体被创建或更新时,ABP 自动发布 `EntityCreatedEto<Product>` 或 `EntityUpdatedEto<Product>` 事件。
`ProductEventHandler` 订阅这些事件,处理逻辑(如记录日志)。
3. AutoMapper 映射:
`WMSManagementDomainMapperProfile` 确保 `Product` 的扩展属性(如 `BatchNumber`)被映射到 `ProductDto`。
使用示例
假设你通过仓储(`IRepository<Product, Guid>`)创建或更新 `Product`:
```csharp
public class ProductAppService : ApplicationService
{
private readonly IRepository<Product, Guid> _productRepository;
public ProductAppService(IRepository<Product, Guid> productRepository)
{
_productRepository = productRepository;
}
public async Task CreateProductAsync(string name, decimal price, string batchNumber)
{
var product = new Product
{
Name = name,
Price = price
};
product.SetProperty("BatchNumber", batchNumber); // 设置扩展属性
await _productRepository.InsertAsync(product);
}
}
```
执行流程:
1. 创建 `Product` 实体,设置 `BatchNumber` 扩展属性。
2. 保存到数据库,触发 `EntityCreatedEto<Product>` 事件。
3. `ProductEventHandler` 捕获事件,打印日志(或执行其他逻辑)。
配置数据库
为确保 `ExtraProperties` 正确存储,需配置 Entity Framework Core 支持 JSON 列。例如,在 `DbContext` 中:
```csharp
public class WMSManagementDbContext : AbpDbContext<WMSManagementDbContext>
{
public DbSet<Product> Products { get; set; }
public WMSManagementDbContext(DbContextOptions<WMSManagementDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Product>(b =>
{
b.Property(x => x.ExtraProperties)
.HasColumnType("nvarchar(max)") // SQL Server 示例
.HasConversion(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),
v => JsonSerializer.Deserialize<ExtraPropertyDictionary>(v, (JsonSerializerOptions)null));
});
}
}
```
说明:配置 `ExtraProperties` 使用 JSON 序列化存储,适用于 SQL Server(`nvarchar(max)`)。
改进建议
1. 事件处理逻辑:
根据业务需求扩展 `ProductEventHandler`,例如调用外部 API 或更新其他实体。
添加错误处理和重试机制,确保分布式事件可靠。
2. 扩展属性验证:
为 `BatchNumber` 添加验证规则(例如,长度限制或格式检查),可在 `ObjectExtensionManager` 中配置。
3. 性能优化:
如果 `BatchNumber` 是高频访问字段,考虑将其提升为 `Product` 实体的固定属性,减少 `ExtraProperties` 的使用。
4. 消息队列:
配置分布式事件总线使用 RabbitMQ 或 Kafka,确保事件在分布式系统中可靠传递。
总结
以上代码实现了:
为 `Product` 实体添加 `BatchNumber` 扩展属性,动态存储在 `ExtraProperties` 中。
配置分布式事件,当 `Product` 创建或更新时自动触发。
提供事件处理器 `ProductEventHandler`,处理事件并访问扩展属性。
确保 AutoMapper 正确映射扩展属性,支持 DTO 转换。
这些功能适合仓储管理系统(WMS)场景,例如动态管理产品属性并通知其他服务。如果你需要进一步定制(例如添加更多扩展属性、复杂事件处理逻辑或 UI 集成),请告诉我!