博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
幸福框架:在应用层实现触发器
阅读量:6049 次
发布时间:2019-06-20

本文共 5413 字,大约阅读时间需要 18 分钟。

背景

企业应用开发过程中经常面对一些非功能型需求,如:自动收集和设置审计信息、索引和关系约束,有些非功能需求当然可以用数据库自带的功能,如索引约束,但是应用层视乎也有必要重复一次,因为当违背这种约束的时候我们希望提示给用户友好的信息,如:‘xxx已经存在,xxx必须唯一’,这篇文章我就介绍一个简单的方案应对这种需求。

思路

我觉得数据库的触发器是个好东西,应用层完全可以借用一下,我还认为如果我在应用层实现了触发器,像一些前置条件和后置条件验证也可以用触发器实现(这块我不是很清楚设计的是否合理,还是要引入另外一个继承体系)。

实现

核心类

核心代码

DefaultTriggerService.cs

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 using Microsoft.Practices.ServiceLocation; 8  9 using Happy.Domain;10 11 namespace Happy.Application.Trigger.Internal12 {13     internal sealed class DefaultTriggerService : ITriggerService14     {15         public void ExecuteBeforeInsert
(TAggregateRoot aggregate)16 where TAggregateRoot : AggregateRoot17 {18 var triggers = ServiceLocator19 .Current20 .GetAllInstances
>();21 22 foreach (var trigger in triggers)23 {24 trigger.BeforeInsert(aggregate);25 }26 }27 28 public void ExecuteAfterInsert
(TAggregateRoot aggregate)29 where TAggregateRoot : AggregateRoot30 {31 var triggers = ServiceLocator32 .Current33 .GetAllInstances
>();34 35 foreach (var trigger in triggers)36 {37 trigger.AfterInsert(aggregate);38 }39 }40 41 public void ExecuteBeforeUpdate
(TAggregateRoot aggregate)42 where TAggregateRoot : AggregateRoot43 {44 var triggers = ServiceLocator45 .Current46 .GetAllInstances
>();47 48 foreach (var trigger in triggers)49 {50 trigger.BeforeUpdate(aggregate);51 }52 }53 54 public void ExecuteAfterUpdate
(TAggregateRoot aggregate)55 where TAggregateRoot : AggregateRoot56 {57 var triggers = ServiceLocator58 .Current59 .GetAllInstances
>();60 61 foreach (var trigger in triggers)62 {63 trigger.AfterUpdate(aggregate);64 }65 }66 67 public void ExecuteBeforeDelete
(TAggregateRoot aggregate)68 where TAggregateRoot : AggregateRoot69 {70 var triggers = ServiceLocator71 .Current72 .GetAllInstances
>();73 74 foreach (var trigger in triggers)75 {76 trigger.BeforeDelete(aggregate);77 }78 }79 80 public void ExecuteAfterDelete
(TAggregateRoot aggregate)81 where TAggregateRoot : AggregateRoot82 {83 var triggers = ServiceLocator84 .Current85 .GetAllInstances
>();86 87 foreach (var trigger in triggers)88 {89 trigger.AfterDelete(aggregate);90 }91 }92 }93 }

自动管理树形节点的路径信息

代码

ITreeNode.cs

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 namespace Happy.Domain.Feature 8 { 9     /// 10     /// 树的节点。11     /// 12     public interface ITreeNode13     {14         /// 15         /// 节点ID。16         /// 17         Guid Id { get; set; }18 19         /// 20         /// 父节点ID。21         /// 22         Guid ParentId { get; set; }23 24         /// 25         /// 节点在树中的路径,如:/A/B/C/D,包含自己。26         /// 27         string NodePath { get; set; }28     }29 }

TreeNodeTrigger.cs

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 using Happy.ExtensionMethod; 8 using Happy.Domain; 9 using Happy.Domain.Feature;10 using Happy.Application.Trigger;11 12 namespace Happy.EntityFramework.Trigger13 {14     public class TreeNodeTrigger
: TriggerBase
15 where TUnitOfWork : UnitOfWork16 where TAgggregateRoot : AggregateRoot, ITreeNode17 {18 public override void BeforeInsert(TAgggregateRoot aggregate)19 {20 var parentNodePath = this.GetParentNodePath(aggregate);21 22 aggregate.NodePath = parentNodePath + "/" + aggregate.Id;23 }24 25 public override void BeforeUpdate(TAgggregateRoot aggregate)26 {27 var newParentNodePath = this.GetParentNodePath(aggregate);28 var newNodePath = newParentNodePath + "/" + aggregate.Id;29 var oldNodePath = aggregate.NodePath;30 31 if (oldNodePath == newNodePath)32 {33 return;34 }35 36 aggregate.NodePath = newNodePath;37 38 var table = typeof(TAgggregateRoot).Name.ToPluralize();39 var sql = string.Format("UPDATE {0} SET NodePath = REPLACE(NodePath, {
{0}}, {
{1}}) WHERE NodePath LIKE {
{2}}", table);40 this.UnitOfWork.Database.ExecuteSqlCommand(sql, oldNodePath, newNodePath, oldNodePath + "/%");41 }42 43 public override void BeforeDelete(TAgggregateRoot aggregate)44 {45 var table = typeof(TAgggregateRoot).Name.ToPluralize();46 var sql = string.Format("DELETE FROM {0} WHERE NodePath LIKE {
{0}}", table);47 this.UnitOfWork.Database.ExecuteSqlCommand(sql, aggregate.NodePath + "/%");48 }49 50 private string GetParentNodePath(TAgggregateRoot aggregate)51 {52 var table = typeof(TAgggregateRoot).Name.ToPluralize();53 var sql = string.Format("SELECT NodePath FROM {0} WHERE Id = {
{0}}", table);54 return this.UnitOfWork.Database.SqlQuery
(sql, aggregate.ParentId).FirstOrDefault();55 }56 }57 }

运行效果

备注

这种触发器我在项目中有用过,虽然有所不足,如批量操作性能不高,但是在很多场景下,也减少了不少的重复代码。

 

转载地址:http://ipxex.baihongyu.com/

你可能感兴趣的文章
2013年7月12日“修复 Migration 测试发现的 Bug”
查看>>
学习vue中遇到的报错,特此记录下来
查看>>
CentOS7 编译安装 Mariadb
查看>>
jstl格式化时间
查看>>
一则关于运算符的小例
查看>>
cronexpression 详解
查看>>
一周小程序学习 第1天
查看>>
小孩的linux
查看>>
JavaScript History对象
查看>>
在 Windows 下安装 Oracle 11g XE (Express Edition)
查看>>
ListView优化
查看>>
【原创】 PostgreSQL 实现MySQL 的auto_increment 字段
查看>>
vs2015添加vc助手
查看>>
检测点1.1
查看>>
android--------阿里 AndFix 热修复
查看>>
control.add()
查看>>
Sublime text3中配置Github
查看>>
Asp.net,C# 加密解密字符串
查看>>
网页视频播放器插件源码
查看>>
2019-4-23 plan
查看>>