幸福框架:准备抽象NHibernate和EntityFramework,大家给点意见
背景
考虑到目前中小企业应用的主流是ORM,我准备在NHibernate和EntityFramework之间找到一个抽象层,也就是说我准备只支持NHibernate和EntityFramework。
思路
NH和EF都实现了“工作单元”和“主键映射”这两种企业应用模式,而这两种模式其实就是管理一种状态机,如下图:
实现
工作单元接口
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
8 {
9 /// <summary>
10 /// 工作单元接口。
11 /// </summary>
12 /// <remarks>
13 /// 聚合状态:
14 /// <list type="number">
15 /// <item>transient:实例存在于内存中,但不存在于工作单元和数据库中。</item>
16 /// <item>persistent in database:实例存在于数据库中。</item>
17 /// <item>persistent in unitofwork:实例存在于工作单元中。</item>
18 /// <item>detached:实例存在于内存和数据库中,但不存在于工作单元中。</item>
19 /// </list>
20 /// 合法转换:
21 /// <list type="number">
22 /// <item>transient > Save -> persistent in unitofwork,Flush时会生成Insert Sql,场景:从UI层创建实例,执行创建。</item>
23 /// <item>detached -> Update -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,执行修改(支持离线乐观并发)。</item>
24 /// <item>detached -> Persist -> persistent in unitofwork,Flush时不会生成Sql,场景:将实例从另一个工作单元脱钩,添加到当前工作单元。</item>
25 /// <item>detached -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从UI层重建实例,删除记录。</item>
26 /// <item>detached -> Merge -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,合并到从数据库重建的实例,执行修改(不支持离线乐观并发)。</item>
27 /// <item>persistent in unitofwork -> Evict -> detached,Flush时不会生成Sql,场景:将实例从当前工作单元脱钩,添加到另一个工作单元。</item>
28 /// <item>persistent in unitofwork -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从数据库重建实例,删除记录。</item>
29 /// <item>persistent in unitofwork -> Flush -> persistent in database,提交工作单元,会生成SQL,场景:执行完一系列Create、Update和Delete后统一提交,只产生一次数据库往返。</item>
30 /// <item>persistent in database -> Load -> persistent in unitofwork,从数据库重建实例。</item>
31 /// <item>persistent in database -> Refresh -> persistent in unitofwork,从数据库刷新实例,场景:使用存储过程修改了一个实例,使用此方法重新刷新一下。</item>
32 /// </list>
33 /// </remarks>
34 public interface IUnitOfWork : IDisposable
35 {
36 /// <summary>
37 /// 判断<paramref name="item"/>是否 persistent in unitofwork。
38 /// </summary>
39 bool Contains<TAggregateRoot>(TAggregateRoot item)
40 where TAggregateRoot : AggregateRoot;
41
42 /// <summary>
43 /// transient > Save -> persistent in unitofwork,Flush时会生成Insert Sql,场景:从UI层创建实例,执行创建。
44 /// </summary>
45 void Save<TAggregateRoot>(TAggregateRoot item)
46 where TAggregateRoot : AggregateRoot;
47
48 /// <summary>
49 /// detached -> Update -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,执行修改(支持离线乐观并发)。
50 /// </summary>
51 void Update<TAggregateRoot>(TAggregateRoot item)
52 where TAggregateRoot : AggregateRoot;
53
54 /// <summary>
55 /// detached -> Persist -> persistent in unitofwork,Flush时不会生成Sql,场景:将实例从另一个工作单元脱钩,添加到当前工作单元。
56 /// </summary>
57 void Persist<TAggregateRoot>(TAggregateRoot item)
58 where TAggregateRoot : AggregateRoot;
59
60 /// <summary>
61 /// 执行如下两种转换:
62 /// <list type="number">
63 /// <item>detached -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从UI层重建实例,删除记录。</item>
64 /// <item>persistent in unitofwork -> Delete -> persistent in unitofwork,Flush时会生成Delete Sql,场景:从数据库重建实例,删除记录。</item>
65 /// </list>
66 /// </summary>
67 void Delete<TAggregateRoot>(TAggregateRoot item)
68 where TAggregateRoot : AggregateRoot;
69
70 /// <summary>
71 /// detached -> Merge -> persistent in unitofwork,Flush时会生成Update Sql,场景:从UI层重建实例,合并到从数据库重建的实例,执行修改(不支持离线乐观并发)。
72 /// </summary>
73 void Merge<TAggregateRoot>(TAggregateRoot item)
74 where TAggregateRoot : AggregateRoot;
75
76 /// <summary>
77 /// persistent in unitofwork -> Evict -> detached,Flush时不会生成Sql,场景:将实例从当前工作单元脱钩,添加到另一个工作单元。
78 /// </summary>
79 void Evict<TAggregateRoot>(TAggregateRoot item)
80 where TAggregateRoot : AggregateRoot;
81
82 /// <summary>
83 /// persistent in unitofwork -> Flush -> persistent in database,提交工作单元,会生成SQL,场景:执行完一系列Create、Update和Delete后统一提交,只产生一次数据库往返。
84 /// </summary>
85 void Flush();
86
87 /// <summary>
88 /// persistent in database -> Load -> persistent in unitofwork,从数据库重建实例。
89 /// </summary>
90 TAggregateRoot Load<TAggregateRoot>(Guid id)
91 where TAggregateRoot : AggregateRoot;
92
93 /// <summary>
94 /// persistent in database -> Refresh -> persistent in unitofwork,从数据库刷新实例,场景:使用存储过程修改了一个实例,使用此方法重新刷新一下。
95 /// </summary>
96 void Refresh<TAggregateRoot>(TAggregateRoot item)
97 where TAggregateRoot : AggregateRoot;
98
99 /// <summary>
100 /// 回滚所有自上次提交以后的修改。
101 /// </summary>
102 void Clear();
103
104 /// <summary>
105 /// 清空处于persistent in unitofwork状态的实例。
106 /// </summary>
107 TRepository GetRepository<TRepository>()
108 where TRepository : IRepository;
109 }
110 }
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Data;
7 using System.Data.Entity;
8 using System.Data.Entity.Infrastructure;
9
10 using Microsoft.Practices.ServiceLocation;
11
12 using Happy.Domain;
13 using Happy.DesignByContract;
14
15 namespace Happy.EntityFramework
16 {
17 /// <summary>
18 /// 基于EntityFramework的工作单元。
19 /// </summary>
20 public abstract class UnitOfWork : DbContext, IUnitOfWork
21 {
22 private readonly Dictionary<Type, IRepository> repositories = new Dictionary<Type, IRepository>();
23
24 /// <summary>
25 /// 构造方法。
26 /// </summary>
27 protected UnitOfWork()
28 {
29 }
30
31 /// <summary>
32 /// 构造方法。
33 /// </summary>
34 protected UnitOfWork(string nameOrConnectionString)
35 : base(nameOrConnectionString)
36 {
37 }
38
39 /// <inheritdoc />
40 public bool Contains<TAggregateRoot>(TAggregateRoot item)
41 where TAggregateRoot : AggregateRoot
42 {
43 item.MustNotNull("item");
44
45 return this.Entry(item).State != EntityState.Detached;
46 }
47
48 /// <inheritdoc />
49 public void Save<TAggregateRoot>(TAggregateRoot item)
50 where TAggregateRoot : AggregateRoot
51 {
52 item.MustNotNull("item");
53
54 this.Set<TAggregateRoot>().Add(item);
55 }
56
57 /// <inheritdoc />
58 public void Update<TAggregateRoot>(TAggregateRoot item)
59 where TAggregateRoot : AggregateRoot
60 {
61 item.MustNotNull("item");
62
63 this.Entry(item).State = EntityState.Modified;
64 }
65
66 /// <inheritdoc />
67 public void Persist<TAggregateRoot>(TAggregateRoot item)
68 where TAggregateRoot : AggregateRoot
69 {
70 item.MustNotNull("item");
71
72 this.Entry(item).State = EntityState.Unchanged;
73 }
74
75 /// <inheritdoc />
76 public void Delete<TAggregateRoot>(TAggregateRoot item)
77 where TAggregateRoot : AggregateRoot
78 {
79 item.MustNotNull("item");
80
81 this.Entry(item).State = EntityState.Deleted;
82 }
83
84 /// <inheritdoc />
85 public void Merge<TAggregateRoot>(TAggregateRoot item)
86 where TAggregateRoot : AggregateRoot
87 {
88 item.MustNotNull("item");
89
90 var persistItem = this.Set<TAggregateRoot>().Find(item.Id);
91
92 this.Entry(persistItem).CurrentValues.SetValues(item);
93 }
94
95 /// <inheritdoc />
96 public void Evict<TAggregateRoot>(TAggregateRoot item)
97 where TAggregateRoot : AggregateRoot
98 {
99 item.MustNotNull("item");
100
101 this.Entry(item).State = EntityState.Detached;
102 }
103
104 /// <inheritdoc />
105 public void Flush()
106 {
107 try
108 {
109 base.SaveChanges();
110 }
111 catch (DbUpdateConcurrencyException ex)
112 {
113 throw new OptimisticConcurrencyException(ex.Message, ex);
114 }
115 }
116
117 public TAggregateRoot Load<TAggregateRoot>(Guid id)
118 where TAggregateRoot : AggregateRoot
119 {
120 return this.Set<TAggregateRoot>().Find(id);
121 }
122
123 public void Refresh<TAggregateRoot>(TAggregateRoot item)
124 where TAggregateRoot : AggregateRoot
125 {
126 item.MustNotNull("item");
127
128 this.Entry(item).Reload();
129 }
130
131 /// <inheritdoc />
132 public void Clear()
133 {
134 base.ChangeTracker.Entries()
135 .ToList()
136 .ForEach(entry => entry.State = System.Data.EntityState.Detached);
137 }
138
139 /// <inheritdoc />
140 public TRepository GetRepository<TRepository>()
141 where TRepository : IRepository
142 {
143 var key = typeof(TRepository);
144
145 if (!repositories.ContainsKey(key))
146 {
147 var repository = ServiceLocator.Current.GetInstance<TRepository>();
148 (repository as IEntityFrameworkRepository).Owner = this;
149 repositories[key] = repository;
150 }
151
152 return (TRepository)repositories[key];
153 }
154 }
155 }
备注
框架地址:http://happy.codeplex.com