首页 > 其他分享 >ABP-VNEXT 学习笔记(六)事件总线--本地事件总线2

ABP-VNEXT 学习笔记(六)事件总线--本地事件总线2

时间:2022-09-22 14:36:14浏览次数:50  
标签:VNEXT -- 数据库 实体 总线 发布 事件 using public

在上一篇中,我们学习介绍了Abp本地事件的基础应用,但都没有涉及到数据库层面的执行。

在数据操作上,abp也提供了很好的事件处理机制,针对数据的增删改操作默认发布了事件,我们只需要订阅对应事件即可。

同时,在上一篇中,我们也提供了abp的订阅是非原子性的,也就是订阅端如果处理失败,是没有事务回滚或者重试的机制的。

那么对应到数据处理,我们就需要在数据的变更前、后做对应处理,比如等前置事件变更到数据库成功后,才处理订阅事件。

对此,abp也提供了对应的事件。

我们定义了一个学生Student类,还有一个积分Score类,当执行insert学生前和后,我们就写入积分。

我们在Student实体中定义了ChangeScoreCount方法,在该方法发布事件:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;

namespace EventBus
{
    public class Student:AggregateRoot<Guid>
    {

        [DisplayName("姓名")]
        public string Name { get; set; }

        [DisplayName("年龄")]
        public int Age { get; set; }


        public void ChangeScoreCount(int score)
        {
            //ADD an EVENT TO BE PUBLISHED
            AddLocalEvent(
                new ScoreCountChangedEvent
                {
                    StudentId = this.Id,
                    Score = score
                }
            );
        }
    }

    public class ScoreCountChangedEvent
    {
        public Guid StudentId { get; set; }

        public int Score { get; set; }

    }
}

如果我们的实体继承了AggregateRoot 聚合根,那在实体类中可使用AddLocalEvent 方法进行事件的发布,否则就使用上一篇中讲述的ILocalEventBus进行发布即可。

AggregateRoot 类定义了 AddLocalEvent 来添加一个新的本地事件,事件在聚合根对象保存(创建,更新或删除)到数据库时发布.

然后,我们在应用层的StudentService类中定义student的写入方法,并执行ChangeScoreCount

using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace EventBus
{
    public class StudentService : ApplicationService,IStudentService
    {
        public IRepository<Student, Guid> studentRepository { get; set; }
        public async Task<bool> InsertAsync(string name, int age)
        {
                var model = new Student() { Name = name, Age = age };
                await studentRepository.InsertAsync(model);
                model.ChangeScoreCount(new Random().Next()); //调用积分变更方法,执行事件发布
            return true;
        }

       
    }
}

在home控制器中定义方法调用student的InsertAsync方法

       public async Task<IActionResult> Test()
        {
           await studentService.InsertAsync("张三", new Random().Next());

            return Ok("Ok");
        }

接下来,我们定义订阅函数,新建一个StudentHandler类来订阅学生的事件

using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;

namespace EventBus.Models
{
    public class StudentHandler
        : ILocalEventHandler<ScoreCountChangedEvent>,ILocalEventHandler<EntityCreatedEventData<Student>>, ILocalEventHandler<EntityCreatingEventData<Student>>
          , ITransientDependency
    {

       public IScoreService scoreService { get; set; }
        public async Task HandleEventAsync(ScoreCountChangedEvent eventData)
        {
            //TODO: your code that does somthing on the event

           await scoreService.AddScoreAsync(eventData.StudentId, eventData.Score);
            Console.WriteLine("学生积分订阅完成");
        }

        //当实体写入数据库之后执行
        public async Task HandleEventAsync(EntityCreatedEventData<Student> eventData)
        {
            await scoreService.AddScoreAsync(eventData.Entity.Id, 10);
            Console.WriteLine("实体写入成功后执行");
        }
        /// <summary>
        /// 实体写入数据库之前执行
        /// </summary>
        /// <param name="eventData"></param>
        /// <returns></returns>
        public async Task HandleEventAsync(EntityCreatingEventData<Student> eventData)
        {
            await scoreService.AddScoreAsync(eventData.Entity.Id, 10);
            Console.WriteLine("实体写入前执行");
        }
    }
}

这里,我们总共订阅了3个事件

1:ScoreCountChangedEvent事件,是我们在StudentService方法中主动发布的事件

2:EntityCreatedEventData<Student>事件,是abp默认发布的,在实体写入数据库成功之后发布的事件

3:EntityCreatingEventData<Student>事件,是abp默认发布的,在实体写入数据库之前发布的事件。

这里面关键的就是在进入数据前后分别都有对应的事件可以订阅处理。

下面,我们运行起来,看下执行顺序

 

 

通过运行后的结果,可以看到实体写入前后的顺序是遵循规则来的。

abp还发布了其他事件:

用过去时态事件

当相关工作单元完成且实体更改成功保存到数据库时,将发布带有过去时态的事件. 如果在这些事件处理程序上抛出异常,则无法回滚事务,因为事务已经提交.

事件类型;

  • EntityCreatedEventData<T> 当实体创建成功后发布.
  • EntityUpdatedEventData<T> 当实体更新成功后发布.
  • EntityDeletedEventData<T> 当实体删除成功后发布.
  • EntityChangedEventData<T> 当实体创建,更新,删除后发布. 如果你需要监听任何类型的更改,它是一种快捷方式 - 而不是订阅单个事件.

用于进行时态事件

带有进行时态的事件在完成事务之前发布(如果数据库事务由所使用的数据库提供程序支持). 如果在这些事件处理程序上抛出异常,它会回滚事务,因为事务还没有完成,更改也没有保存到数据库中.

事件类型;

  • EntityCreatingEventData<T> 当新实体保存到数据库前发布.
  • EntityUpdatingEventData<T> 当已存在实体更新到数据库前发布.
  • EntityDeletingEventData<T> 删除实体前发布.
  • EntityChangingEventData<T> 当实体创建,更新,删除前发布. 如果你需要监听任何类型的更改,它是一种快捷方式 - 而不是订阅单个事件.

它是如何实现的?

在将更改保存到数据库时发布预构建事件;

  • 对于 EF Core, 他们在 DbContext.SaveChanges 发布.
  • 对于 MongoDB, 在你调用仓储的 InsertAsyncUpdateAsync 或 DeleteAsync 方法发布(因为MongoDB没有更改追踪系统).

 

以上两篇文章,就是abp在本地事件发布的相关应用分享。

更多分享,请大家关注我的个人公众号:

 

 

标签:VNEXT,--,数据库,实体,总线,发布,事件,using,public
From: https://www.cnblogs.com/fei686868/p/16719135.html

相关文章

  • 39. [实例]Scrapy框架应用
    1.前言通过上一节《PythonScrapy爬虫框架详解》的学习,您已经对Scrapy框架有了一个初步的认识,比如它的组件构成,配置文件,以及工作流程。本节将通过一个的简单爬虫项目对......
  • 基于深度强化学习的交通信号灯控制从入门到放弃(持续更新)
    目录理论书籍博客代码论文理论书籍博客MARL多智能体强化学习分享KDDCUP2021参赛感悟及论文解读代码论文......
  • JSTL标签库(JSP标准标签库)
    JSTL标签库(JSP标准标签库)JSTL(JSPStandardTagLibrary,核心标签库)是JSP标签的集合,它封装了JSP应用的通用核心功能。JSP标签是一组与HTML标签相似,但又比HTML标签......
  • TCP的三次握手与四次挥手理解
     序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号......
  • Linux系统安装was9
    把was9.0安装文件传到我们的服务器上一共6个IM、sdk、IHS、9.0.0-WS-WAS-FP010、WAS_ND_V9.0_MP_ML、PLUGINS 进到目录下进行依次解压缩[[email protected]......
  • 教你如何将二进制文件导入到数据库
    教你如何将二进制文件导入到数据库1.1现网业务场景源数据推送二进制流-->解析二进制-->解析后的数据导入数据库为了模拟生产的业务场景,客户提供了一个二进制文件及......
  • vue3+ts+elementui中的手动上传至服务器
    <el-uploadclass="inline"ref="uploadImgRef":http-request="uploadImg":auto-upload="false":accept="'.jpg,.png'"><template#trigger><el-butto......
  • Spring 后置处理器【1】
    Spring后置处理器【1】简单介绍一句话:bean在初始化前或初始化后的瞬间,我自己添加一些业务逻辑bean后置处理器类的内容简单代码packagecom.hspedu.spring.bean;......
  • 前端打印dom
    方法一constprintWindow=window.open()printWindow.document.write(document.querySelector('#printBox').innerHTML)printWindow.print()......
  • 反射
    java是一门编译型语言;与之对应的称之为解释性(JavaScript,python)。编译型语言在编写完源代码后必须要编译之后才能够运行。解释性语言内置了解释器,程序一边解释,一边执行。ja......