自定义应用模块: 扩展实体

    是一种存储实体的一些额外数据但不用更改实体的方式. 实体应该实现 接口. 所有预构建模块定义的聚合根实体都实现了 IHasExtraProperties 接口,所以你可以在这些实体中存储额外的属性.

    示例:

    这种方法开箱即用并且非常简单,你可以使用不同的属性名称(如这里的Title)在同一时间存储多个属性.

    对于EF Core额外的属性被格式化成单个 JSON 字符值串存储在数据库中. 对于MongoDB它们做为单独的字段存储.

    参阅实体文档了解更多关于额外系统.

    如上所述,实体所有的额外属性都作为单个JSON对象存储在数据库表中. 它不适用复杂的场景,特别是在你需要的时候.

    • 使用额外属性创建索引外键.
    • 使用额外属性编写SQLLINQ(例如根据属性值搜索).
    • 创建你自己的实体映射到相同的表,但在实体中定义一个额外属性做为 常规属性(参阅 了解更多).

    假设你想要添加 SocialSecurityNumber身份模块IdentityUser 实体. 你可以使用 ObjectExtensionManager 类:

    • 你提供了 IdentityUser 作为实体名(泛型参数), 做为新属性的类型, SocialSecurityNumber 做为属性名(也是数据库表的字段名).
    • 你还需要提供一个使用定义数据库映射属性的操作.

    定义实体扩展后你需要使用EF Core的Add-Migration和命令来创建code first迁移类并更新数据库.

    然后你可以使用上一部分中定义的相同额外属性系统来操纵实体上的属性.

    另一个方法是创建你自己的实体映射到同一个数据库库(对于MongoDB数据库是collection)

    应用程序启动模板AppUser 已经实现了这种方法. 描述了在这些情况下如何实现和管理EF Core数据库迁移. 这种方法同样适用于MongoDB,但你不需要处理数据库迁移问题.

    映射你的实体到依赖模块的已存在的表有一些缺点;

    • 你需要处理EF Core的数据库迁移架构. 需要特别注意迁移代码,特别是当你需要在实体间添加关系时.

    在这种情况下你需要处理同步问题,尤其是你要复制相关实体的某些属性/字段时,有一些解决方案;

    • 如果你构建的是一个 单体 应用程序(或者在同一进程管理你的实体和依赖模块的实体),那么你可以使用本地事件总线监听实体更改.
    • 如果你构建的是一个 分布式 系统,模块的实体和你的实体在不同的 进程/服务 管理(创建/更新/删除),那么你可以使用订阅实体的更改事件.

    在你处理事件时,你可以在自己的数据库中更改自己的实体.

    本地事件总线系统是发布和订阅同一应用程序中发生的事件的方法.

    假设你想要获取 IdentityUser 实体的更改信息(创建,更改或删除). 你可以创建一个类实现 ILocalEventHandler<EntityChangedEventData<IdentityUser>> 接口.

    • EntityChangedEventData<T> 涵盖了给定实体的创建,更新或删除事件. 如果你需要你可以分别订阅创建,更新或删除事件(在同一个类或不同的类中).
    • 这里的代码在本地事务之外执行,因为它监听 事件. 如果当前是事务性的,你可以订阅 EntityChangingEventData<T> 事件,它在同一本地(进行)事务中执行事件处理.

    订阅分布式事件总线

    分布式事件总线是在一个应用程序中发布事件,并在相同服务器或不同服务器运行的相同应用程序或不同应用程序中接收事件的方法.

    假设你想要获取 IdentityUser 实体的创建,更改或删除信息. 你可以像以下一样创建一个类:

    • 它实现了多个 IDistributedEventHandler 接口: 创建,更改删除,因为分布式事件总线单独发布事件,没有本地事件总线那样的”Changed”事件.
    • 它订阅了 EntityEto, 这是一个通用的事件类,ABP框架针对所有类型的实体自动发布. 这就是为什么它检查实体类型(因为我们没有假设有对 IdentityUser 实体有安全的类型引用,所以它是字符串类型的).