UnitOfWork机制的实现和注意事项
UnitOfWork机制
/*一点牢骚:
* UnitOfWork机制的蛋疼之处:
* UnitOfWork机制,决定了插入新的实体前,要预先设置数据库中的主键Id,尽管数据库自己生产主键。
* 但是,如果自己能生成主键还要数据库自动生成主键干什么,即使自己生成主键不能保证主键的唯一性,
* 除非主键是GUID。
*
* if (!addedEntities.ContainsKey(entity))
{
addedEntities.Add(entity, unitofWorkRepository);
};
* 判断实体的唯一性标准是调用实体的GetHashCode();
* public override int GetHashCode()
{
return this.Id.GetHashCode();
}
*而 this.Id是实体在数据库的主键(一般用数据库自动生成),但我插入前怎么能由我生成能。
*如果人工生成不能保证主键的唯一性,就不能添加到所以addedEntities中,也就不能保存到数据库。
*折中的解决方案是每添加一个新的实体,就Commit一次(马上提交到数据库,并清空addedEntities)。
*
*/
---------------------------------------------------------冷静分割线---------------------------------------------------
仓储实现UintOfWork机制
1.目标:
实现仓储实现UintOfWork机制(UintOfWork机制的目的是实现实体的持久化操作的原子性,保证数据的一致性)
2.具体的实现思路:
图解:
伪代码:
(1)仓储类Repository的定义
Repository类
{
虚拟增(实体entity) {
UintOfWork对象.增登记(实体entity,this) }; 虚拟删(实体entity) {
UintOfWork对象.删登记(实体entity,this) }; 虚拟改Add(实体entity) {
UintOfWork对象. 改登记(实体entity,this) }; 真的增到数据库(实体entity) {
AddTo数据库(实体entity)
}; 真的删到数据库(实体entity) {
RemovFrom数据库(实体entity)
}; 真的改保存到数据库(实体entity) {
UpdateTo数据库(实体entity)
};
}
(2)UnitOfWork类的定义:
UnitOfWork
{ 被增实体的字典 = new ();
被删实体的字典 = new ();
被改实体的字典 = new(); 增登记(实体entity,Repository)
{
if(如果被增实体的字典包不含实体entity)
被增实体的字典.Add(实体entity,Repository);
} 删登记(实体entity,Repository)
{
if (如果被删实体的字典不包含实体enity)
被删实体的字典.Add(实体entity,Repository);
} 改登记(实体entity,Repository)
{ if(如果被改实体的字典不包含实体entity)
被改实体的字典.Add(实体entity,Repository);
} 统一提交到数据库Commit()
{
for(int i = ; i < 被增实体的字典.lengh; ++i )
{
实体entity tmpEntity = 被增实体的字典[i].Key;
Repository repository = 被增实体的字典[i].Value;
repository.真的增保存到数据库(tmpEntity);
} for(int i = ; i < 被删实体的字典.lengh; ++i )
{
实体entity tmpEntity = 被删实体的字典[i].Key;
Repository repository = 被删实体的字典[i].Value;
repository.真的删保存到数据库(tmpEntity);
} for(int i = ; i < 被改实体的字典.lengh; ++i )
{
实体entity tmpEntity = 被改实体的字典[i].Key;
Repository repository = 被改实体的字典[i].Value;
repository.真的改保存到数据库(tmpEntity);
}
}
}
3.光说不练,代码实现:
IUnitOfWorkRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NCS.Infrastructure.Domain; namespace NCS.Infrastructure.UnitOfWork
{
/// <summary>
/// Repository实现了UnitOfWork机制的Repository
/// </summary>
public interface IUnitOfWorkRepository
{
/// <summary>
/// 实体的持久化操作(包括三个操作:增Add、删remove、改save,注意不包括查询)前,
/// 先用UnitOfWork进行登记,
/// 以便日后由UnitOfWork统一(原子性)通过Commit操作,提交修改到数据库(持久化操作)
/// </summary>
IUnitOfWork UnitOfWork { get; set; } /**
* Persist持久化系列函数
*/
void PersistCreationOf(IAggregateRoot entity);
void PersistUpdateOf(IAggregateRoot entity);
void PersistDeletionOf(IAggregateRoot entity);
}
}
IUnitOfWork.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NCS.Infrastructure.Domain; namespace NCS.Infrastructure.UnitOfWork
{
/// <summary>
/// UnitOfWork模式:
/// 1.跟踪领域实体聚合的变化
/// 2.原子操作中完成实体聚合的持久化
/// 3.具体实现:
/// 实体的进行持久化操作(包括三个操作:增Add、删remove、改save,注意不包括查询)前,
/// 先用UnitOfWork进行登记,
/// 以便日后由UnitOfWork统一(原子性)通过Commit操作,提交修改到数据库(持久化操作)
/// </summary>
/// </summary>
public interface IUnitOfWork
{
/// <summary>
/// 注册登记被添加的实体
/// </summary>
/// <param name="entity">目标实体</param>
/// <param name="unitofWorkRepository">实体所在的仓储</param>
void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
/// <summary>
/// 注册登记被删除的实体
/// </summary>
/// <param name="entity">目标实体</param>
/// <param name="unitofWorkRepository">实体所在的仓储</param>
void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
/// <summary>
/// 注册登记被修改的实体
/// </summary>
/// <param name="entity">目标实体</param>
/// <param name="unitofWorkRepository">实体所在的仓储</param>
void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository); void Commit();
}
}
AdoUnitOfWork.cs
/*一点牢骚:
* UnitOfWork机制的蛋疼之处:
* UnitOfWork机制,决定了插入新的实体前,要预先设置数据库中的主键Id,尽管数据库自己生产主键。
* 但是,如果自己能生成主键还要数据库自动生成主键干什么,即使自己生成主键不能保证主键的唯一性,
* 除非主键是GUID。
*
* if (!addedEntities.ContainsKey(entity))
{
addedEntities.Add(entity, unitofWorkRepository);
};
* 判断实体的唯一性标准是调用实体的GetHashCode();
* public override int GetHashCode()
{
return this.Id.GetHashCode();
}
*而 this.Id是实体在数据库的主键(一般用数据库自动生成),但我插入前怎么能由我生成呢!!!
*因为:
*1.不知主键的数据库类型;
*2.即使知道主键的数据库类型,也不能因为硬编码造成的依赖,耦合。
*3.人工生成不能保证主键的唯一性,
*综上,所以就不能添加到addedEntities中,也就不能保存到数据库。
*折中的解决方案是每添加一个新的实体,就Commit一次(马上提交到数据库,并清空addedEntities)。
*
*/ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NCS.Infrastructure.Domain;
using NCS.Infrastructure.UnitOfWork;
using System.Transactions; namespace NCS.Repository.ADO
{
public class AdoUnitOfWork : IUnitOfWork
{
private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities; public AdoUnitOfWork()
{
addedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
changedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
deletedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
} #region IUnitOfWork member #region 注册登记实体
public void RegisterNew(IAggregateRoot entity,
IUnitOfWorkRepository unitofWorkRepository)
{
if (!addedEntities.ContainsKey(entity))
{
addedEntities.Add(entity, unitofWorkRepository);
};
} public void RegisterRemoved(IAggregateRoot entity,
IUnitOfWorkRepository unitofWorkRepository)
{
if (!deletedEntities.ContainsKey(entity))
{
deletedEntities.Add(entity, unitofWorkRepository);
}
} public void RegisterAmended(IAggregateRoot entity,
IUnitOfWorkRepository unitofWorkRepository)
{
if (!changedEntities.ContainsKey(entity))
{
changedEntities.Add(entity, unitofWorkRepository);
}
} #endregion
public void Commit()
{
using (TransactionScope scope = new TransactionScope())
{
foreach (IAggregateRoot entity in this.addedEntities.Keys)
{
this.addedEntities[entity].PersistCreationOf(entity);
} foreach (IAggregateRoot entity in this.changedEntities.Keys)
{
this.changedEntities[entity].PersistUpdateOf(entity);
} foreach (IAggregateRoot entity in this.deletedEntities.Keys)
{
this.deletedEntities[entity].PersistDeletionOf(entity);
} scope.Complete(); this.addedEntities.Clear();
this.changedEntities.Clear();
this.deletedEntities.Clear();
}
} #endregion }
}
Repository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NCS.Infrastructure.Domain;
using NCS.Infrastructure.Querying;
using NCS.Infrastructure.UnitOfWork;
using NCS.Repository.ADO.DataSession; namespace NCS.Repository.ADO.Repositories
{
public abstract class Repository<T, TEntityKey> : IUnitOfWorkRepository
where T : IAggregateRoot
{
private IUnitOfWork unitOfWork; private IDataSession<T, TEntityKey> dataSession; public Repository(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
DataSession = DataSessionFactory.GetDataSession<T, TEntityKey>();
} public IUnitOfWork UnitOfWork
{
get { return unitOfWork; }
set { unitOfWork = value; }
} public IDataSession<T, TEntityKey> DataSession
{
get { return dataSession; }
set { dataSession = value; }
} #region 持久化 public void Add(T entity)
{
UnitOfWork.RegisterNew(entity, this);
} public void Remove(T entity)
{
UnitOfWork.RegisterNew(entity, this);
} public void Remove(Query query)
{
//TODO:好像Remove(Query query)并不能保证事务操作,因为没添加到UnitOfWork里面
//先提交事务
unitOfWork.Commit(); DataSession = DataSessionFactory.GetDataSession<T, TEntityKey>();
DataSession.Remove(query); } public void Save(T entity)
{
UnitOfWork.RegisterRemoved(entity, this);
} #endregion #region 查询部分 public T FindBy(TEntityKey id)
{
return this.DataSession.FindBy(id);
} public IEnumerable<T> FindAll()
{
return this.DataSession.FindAll();
} public IEnumerable<T> FindAll(int index, int count)
{
return this.DataSession.FindAll().Skip(index).Take(count);
} public IEnumerable<T> FindBy(Query query)
{
return this.DataSession.FindBy(query);
} public IEnumerable<T> FindBy(Query query, int index, int count)
{
return this.DataSession.FindBy(query, index, count);
} #endregion #region IUnitOfWorkRepository members public virtual void PersistCreationOf(IAggregateRoot entity)
{
this.DataSession.Add((T)entity);
} public virtual void PersistUpdateOf(IAggregateRoot entity)
{
this.DataSession.Save((T)entity);
} public virtual void PersistDeletionOf(IAggregateRoot entity)
{
this.DataSession.Remove((T)entity);
} #endregion }
}
UnitOfWork机制的实现和注意事项的更多相关文章
- docker build 的 cache 机制
cache 机制注意事项 可以说,cache 机制很大程度上做到了镜像的复用,降低存储空间的同时,还大大缩短了构建时间.然而,不得不说的是,想要用好 cache 机制,那就必须了解利用 cache 机 ...
- Node基础篇(模块和NPM)
核心模块 核心模块的意义 如果只是在服务器运行JavaScript代码,意义并不大,因为无法实现任何功能(读写文件,访问网络). Node 的用处在于它本身还提供的一系列功能模块,用于与操作系统互动. ...
- node学习笔记
一.准备(github地址) 什么是Javascript? ... Javascript能做什么? ..... 浏览器中的Javascript可以做什么? 操作DOM(增删改查) AJAX/跨域 BO ...
- 【Bugly干货】Android性能优化典范之多线程篇
本文涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask,HandlerThread,IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项,这是一篇 ...
- Android性能优化典范 - 第5季
这是Android性能优化典范第5季的课程学习笔记,拖拖拉拉很久,记录分享给大家,请多多包涵担待指正!文章共10个段落,涉及的内容有:多线程并发的性能问题,介绍了AsyncTask,HandlerTh ...
- Python_socket常见的方法、网络编程的安全注意事项、socketsever模块、浏览器中在一段时间记录用户的登录验证机制
1.socket常见的方法 socket_常见方法_服务器端 import socket from socket import SOL_SOCKET,SO_REUSEADDR sk = socket. ...
- Golang Vendor 包机制 及 注意事项
现在的 Go 版本是 1.8,早在 1.5 时期,就有了 Vendor 包机制,详情可查看博文:“理解 Go 1.5 vendor”. 遇到的问题 个人在使用 Glide 管理 Vendor 包时(附 ...
- Android消息机制使用注意事项,防止泄漏
在Android的线程通信当中,使用频率最多的就是Android的消息处理机制(Handler.send().View.post().Asynctask.excute()等等都使用到了消息处理机制). ...
- Android:onNewIntent()触发机制及注意事项
一.onNewIntent() 在IntentActivity中重写下列方法:onCreate onStart onRestart onResume onPause onStop onDestro ...
随机推荐
- vs2015启动iis express失败
vs2015启动web项目失败,查看日志 IIS Express\aspnetcore.dll 未能加载 ,解决方法 下载 VSorVWDASPNETCore.exe (https://www.asp ...
- 搭建私有git代码托管服务就是这么简单(简单5步)
部署一个git代码托管服务就是这么简单 --基于阿里云ecs以docker容器运行gogs代码托管服务 部署步骤: 1.新建ecs云主机,选定操作系统为ubuntu 12.4tls 2.搭建docke ...
- jQuery概述,代码举例及最新版下载
jQuery是一个快速的,小巧的,具有强大功能的JavaScript库. 它的基本功能包括: 1)访问和操作DOM元素 2)控制页面样式(可以兼容各种浏览器) 3)对页面事件的处理 4)大量插件在页面 ...
- 使用Emmet(前身Zen Coding)加速Web前端开发
Emmet插件以前被称作为Zen Coding,是一个文本编辑器的插件,它可以帮助您快速编写HTML和CSS代码,从而加速Web前端开发.早在2009年,Sergey Chikuyonok写过一篇文章 ...
- sql2000下如何新建并使用dbml
默认新建的dbml只是支持sql2005及其以上版本. 但是现在是sql2000怎么办?我要是想要用linq to sql 的? 解决方案如下: 1首先打开cmd,在其中cd到sqlmetal.exe ...
- (转)操作型数据库的春天:MongoDB 1.5亿美元融资背后的故事
大部分融资都要耗时数月,但非关系式数据库MongoDB仅用3周时间就完成了1.5亿美元的融资.为什么这个进程会这么快,MongoDB CEO Max Schireson在接受采访时说,这是因为投资者看 ...
- CLI结果输出
例子:FTP::11.245.253.20_CIPS_dev_bak\/opt/IBM/db2/V9.7/samples/ 要不要修改整体结构,先看看细节 CLI结果输出: 1. 逐条的获取--确定产 ...
- iOS进阶——可取消的block
+ (id)performBlock:(void (^)())aBlock onQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)del ...
- java运算符新用法和^新认识
public class Demo1 { public static void main(String[] args) { boolean t = false | true; System.out.p ...
- LINQ中实现 In 与 Not In
T-SQL的IN: Select ProductID, ProductName, CategoryID From dbo.Products , ) T-SQL的NOT IN: Select Produ ...