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机制的实现和注意事项的更多相关文章

  1. docker build 的 cache 机制

    cache 机制注意事项 可以说,cache 机制很大程度上做到了镜像的复用,降低存储空间的同时,还大大缩短了构建时间.然而,不得不说的是,想要用好 cache 机制,那就必须了解利用 cache 机 ...

  2. Node基础篇(模块和NPM)

    核心模块 核心模块的意义 如果只是在服务器运行JavaScript代码,意义并不大,因为无法实现任何功能(读写文件,访问网络). Node 的用处在于它本身还提供的一系列功能模块,用于与操作系统互动. ...

  3. node学习笔记

    一.准备(github地址) 什么是Javascript? ... Javascript能做什么? ..... 浏览器中的Javascript可以做什么? 操作DOM(增删改查) AJAX/跨域 BO ...

  4. 【Bugly干货】Android性能优化典范之多线程篇

    本文涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask,HandlerThread,IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项,这是一篇 ...

  5. Android性能优化典范 - 第5季

    这是Android性能优化典范第5季的课程学习笔记,拖拖拉拉很久,记录分享给大家,请多多包涵担待指正!文章共10个段落,涉及的内容有:多线程并发的性能问题,介绍了AsyncTask,HandlerTh ...

  6. Python_socket常见的方法、网络编程的安全注意事项、socketsever模块、浏览器中在一段时间记录用户的登录验证机制

    1.socket常见的方法 socket_常见方法_服务器端 import socket from socket import SOL_SOCKET,SO_REUSEADDR sk = socket. ...

  7. Golang Vendor 包机制 及 注意事项

    现在的 Go 版本是 1.8,早在 1.5 时期,就有了 Vendor 包机制,详情可查看博文:“理解 Go 1.5 vendor”. 遇到的问题 个人在使用 Glide 管理 Vendor 包时(附 ...

  8. Android消息机制使用注意事项,防止泄漏

    在Android的线程通信当中,使用频率最多的就是Android的消息处理机制(Handler.send().View.post().Asynctask.excute()等等都使用到了消息处理机制). ...

  9. Android:onNewIntent()触发机制及注意事项

    一.onNewIntent() 在IntentActivity中重写下列方法:onCreate onStart onRestart  onResume  onPause onStop onDestro ...

随机推荐

  1. 20141016--for 兔子

    Console.Write("请输入月数:"); int m =int.Parse(Console.ReadLine()); ;//成兔对数ct ;//小兔对数xt ;//幼兔对数 ...

  2. Bootstrap学习笔记(二) 表单

    在Bootstrap学习笔记(一) 排版的基础上继续学习Bootstrap的表单,编辑器及head内代码不变. 3-1 基础表单 单中常见的元素主要包括:文本输入框.下拉选择框.单选按钮.复选按钮.文 ...

  3. Unity3D编程回忆录,Unity3d视频教程,教父团队倾情之作

    之前一直在看Unity3d的视频教程,包括很多老外的视频教程,老外的教程确实不错,技术含量很高,而且讲得很激情,让我有种恨不得一秒钟就想吧unity3d学个精通的冲动,只是,毕竟是英语教程,没办法,哎 ...

  4. mysql 报Row size too large 65535 原因与解决方法

    报错信息:Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535 ...

  5. 隐藏win7盘符

    1.隐藏盘符: //新建注册表,隐藏X盘符 int regeditme() { HKEY hkey; DWORD dwLastError= ;//隐藏X盘2^25 J:2^9=512 X:盘符与挂载的 ...

  6. 多项分布(multinominal distribution)

    简介 更一般性的问题会问:“点数1~6的出现次数分别为(x1,x2,x3,x4,x5,x6)时的概率是多少?其中sum(x1~x6)= n”.这就是一个多项式分布. 定义 把二项分布推广至多个(大于2 ...

  7. jQuery网页元素拖拽插件

    效果说明:配合已有CSS样式,载入插件后,网页元素可以随意在窗口内拖拽,设置了原位置半透明和拖拽半透明的效果选项,可根据需要选择.另外,当页面上有多个可拖拽元素时,可以载入另外一个用于设置z-inde ...

  8. document.compatMode的CSS1compat

    document.compatMode BackCompat:标准兼容模式关闭.浏览器宽度:document.body.clientWidth: CSS1Compat:标准兼容模式开启. 浏览器宽度: ...

  9. Windows平台下为Python添加MySQL支持

    到Python官网下载MySQL-python-1.2.5.win32-py2.7.exe 安装MySQL-python-1.2.5.win32-py2.7 附 64位MySQL-python下载地址 ...

  10. 一个基于python的即时通信程序

    5月17日更新: 广播信息.用户列表.信息确认列表以及通信信息,从原来的用字符串存储改为使用字典来存储,使代码更清晰,更容易扩展,具体更改的格式如下: 广播信息(上线): { 'status': 信息 ...