【Yom框架】漫谈个人框架的设计之二:新的IRepository接口+搜索和排序解耦(+基于Castle实现)
经过了上篇IRepository和IRepository<T>的讨论【文章地址为:http://www.cnblogs.com/yomho/p/3296759.html】
我选择了IRepository作为我重构框架的仓储接口
一、接口定义
新的IRepository接口设计如下:
1 namespace Yom.NFramework2_0 2 { 3 public interface IRepository<TCompositeKey> 4 where TCompositeKey : IEquatable<string> 5 { 6 #region 实体操作接口 7 T FindBy<T>(TCompositeKey primaryKey) where T : IEntity; 8 IEnumerable<T> FindAll<T>() where T : IEntity; 9 IEnumerable<T> FindAll<T>(IWhere[] where) where T : IEntity; 10 IEnumerable<T> FindAll<T>(IWhere[] where, IOrder[] order) where T : IEntity; 11 IEnumerable<T> FindAll<T>(int pageIndex, int pageSize, IWhere[] where, IOrder[] order, out int count) where T : IEntity; 12 void Add<T>(T entity) where T : IEntity; 13 void Delete<T>(T entity) where T : IEntity; 14 void DeleteAll<T>() where T : IEntity; 15 void DeleteAll<T>(IWhere[] where) where T : IEntity; 16 void DeleteAll<T>(string where) where T : IEntity; 17 void DeleteAll<T>(IEnumerable<TCompositeKey> pkValues) where T : IEntity; 18 void Update<T>(T entity) where T : IEntity; 19 bool Exists<T>(TCompositeKey primaryKey) where T : IEntity; 20 #endregion 21 #region 静态方法接口 22 int ExecuteSql(string sql, params System.Data.IDataParameter[] ps); 23 object ExecuteScalar(string sql, params System.Data.IDataParameter[] ps); 24 System.Data.DataTable ExecuteDataTable(string sql, params System.Data.IDataParameter[] ps); 25 #endregion 26 } 27 }
其中IEntity和IWhere以及IOrder的设计接口如下:
public interface IEntity { } public interface IOrder { } public interface IWhere { } public interface ICompositeKey : IEquatable<string> { }
ICompositeKey为组合主键接口
为什么ICompositeKey要继承为IEquatable<string>这个接口呢?
因为IEquatable<string>是string的基类,且string为不能继承的类,
所以目的是和string兼容,经过处理可以变成一个string类,从而可以兼容普通的非组合主键。
(此文不讲组合主键的实现原理,展示组合主键接口只是让大家看看组合主键实现解耦的方法)
二、嫁接Castle实现搜索以及排序
很多人不知道怎么把自己的IRepository接口的排序和搜索对象解耦,
在用不同的ORM实现IRepository接口的时候总不知道怎么弄排序和搜索
下面就来看我怎么把Castle的排序和搜索用IOrder以及IWhere解耦的
首先是IOrder -> NHibernate.Expression.Order 的变身
1 namespace Yom.NFramework2_0.CastleExtend 2 { 3 public class OrderBase : NHibernate.Expression.Order, Yom.NFramework2_0.IOrder 4 { 5 public OrderBase(string propertyName, bool ascending) : base(propertyName, ascending) { 6 7 } 8 } 9 }
这个很简单,OrderBase一下子就变成了NHibernate.Expression.Order
那么IWhere是否可以顺利完成像IOrder这种变身么?
研究后发现:Castle是用NHibernate.Expression.Expression的静态方法创建查询对象的
静态方法都是返回NHibernate.Expression.AbstractCriterion抽象类或者ICriterion接口
可以继承这个抽象对象或者接口吧,这样就可以实现变身了!!!
但如果真要这样做,必然有抽象方法要实现,这实在是一个下下策(想嫁接个接口和抽象类不容易吖)
那有没有直接实现NHibernate.Expression.AbstractCriterion抽象类的类呢?
反正我是没有找到,但是Castle肯定有,如果找到这么个类,就可以像IOrder一样实现嫁接,现在没有发现只能想他法。
最后我对WhereBase的变身是:
1 namespace Yom.NFramework2_0.CastleExtend 2 { 3 public class WhereBase : Yom.NFramework2_0.IWhere 4 { 5 public NHibernate.Expression.ICriterion Instance 6 { 7 get; 8 set; 9 } 10 public override string ToString() 11 { 12 return Instance.ToString(); 13 } 14 #region 废弃代码 15 //public static void AllEq(WhereBase where, System.Collections.IDictionary propertyNameValues) 16 //{ 17 // where.Instance = NHibernate.Expression.Expression.AllEq(propertyNameValues); 18 //} 19 //public static void And(WhereBase where, WhereBase whereA, WhereBase whereB) 20 //{ 21 // where.Instance = NHibernate.Expression.Expression.And(whereA.Instance, whereB.Instance); 22 //} 23 //public static void Between(WhereBase where, string propertyName, object lo, object hi) 24 //{ 25 // where.Instance = NHibernate.Expression.Expression.Between(propertyName, lo, hi); 26 //} 27 //public static void Eq(WhereBase where, string propertyName, object value) { 28 // where.Instance = NHibernate.Expression.Expression.Eq(propertyName, value); 29 //} 30 //public static void EqProperty(WhereBase where, string propertyName, string otherPropertyName) 31 //{ 32 // where.Instance = NHibernate.Expression.Expression.EqProperty(propertyName, otherPropertyName); 33 //} 34 //public static void Ge(WhereBase where, string propertyName, object value) 35 //{ 36 // where.Instance = NHibernate.Expression.Expression.Ge(propertyName, value); 37 //} 38 //public static void GeProperty(WhereBase where, string propertyName, string otherPropertyName) 39 //{ 40 // where.Instance = NHibernate.Expression.Expression.GeProperty(propertyName, otherPropertyName); 41 //} 42 //public static void Gt(WhereBase where, string propertyName, object value) 43 //{ 44 // where.Instance = NHibernate.Expression.Expression.Gt(propertyName, value); 45 //} 46 //public static void GtProperty(WhereBase where, string propertyName, string otherPropertyName) 47 //{ 48 // where.Instance = NHibernate.Expression.Expression.GtProperty(propertyName, otherPropertyName); 49 //} 50 //public static void IdEq(WhereBase where, object value) 51 //{ 52 // where.Instance = NHibernate.Expression.Expression.IdEq(value); 53 //} 54 //public static void In(WhereBase where, string propertyName, System.Collections.ICollection values) 55 //{ 56 // where.Instance = NHibernate.Expression.Expression.In(propertyName, values); 57 //} 58 //public static void InG<T>(WhereBase where, string propertyName, ICollection<T> values) 59 //{ 60 // where.Instance = NHibernate.Expression.Expression.InG<T>(propertyName, values); 61 //} 62 //public static void InsensitiveLike(WhereBase where, string propertyName, object value) 63 //{ 64 // where.Instance = NHibernate.Expression.Expression.InsensitiveLike(propertyName, value); 65 //} 66 //public static void IsEmpty(WhereBase where, string propertyName) 67 //{ 68 // where.Instance = NHibernate.Expression.Expression.IsEmpty(propertyName); 69 //} 70 //public static void propertyName(WhereBase where, string propertyName) 71 //{ 72 // where.Instance = NHibernate.Expression.Expression.IsNotEmpty(propertyName); 73 //} 74 //public static void IsNotNull(WhereBase where, string propertyName) 75 //{ 76 // where.Instance = NHibernate.Expression.Expression.IsNotNull(propertyName); 77 //} 78 //public static void IsNull(WhereBase where, string propertyName) 79 //{ 80 // where.Instance = NHibernate.Expression.Expression.IsNull(propertyName); 81 //} 82 //public static void Le(WhereBase where, string propertyName, object value) 83 //{ 84 // where.Instance = NHibernate.Expression.Expression.Le(propertyName, value); 85 //} 86 //public static void LeProperty(WhereBase where, string propertyName, string otherPropertyName) 87 //{ 88 // where.Instance = NHibernate.Expression.Expression.LeProperty(propertyName, otherPropertyName); 89 //} 90 //public static void Like(WhereBase where, string propertyName, string value, NHibernate.Expression.MatchMode matchModes) 91 //{ 92 // where.Instance = NHibernate.Expression.Expression.Like(propertyName, value, matchModes); 93 //} 94 95 //public static void Lt(WhereBase where, string propertyName, object value) 96 //{ 97 // where.Instance = NHibernate.Expression.Expression.Lt(propertyName, value); 98 //} 99 //public static void LtProperty(WhereBase where, string propertyName, string otherPropertyName) 100 //{ 101 // where.Instance = NHibernate.Expression.Expression.LtProperty(propertyName, otherPropertyName); 102 //} 103 //public static void Not(WhereBase where) 104 //{ 105 // where.Instance = NHibernate.Expression.Expression.Not(where.Instance); 106 //} 107 //public static void NotEqProperty(WhereBase where, string propertyName, string otherPropertyName) 108 //{ 109 // where.Instance = NHibernate.Expression.Expression.NotEqProperty(propertyName, otherPropertyName); 110 //} 111 //public static void Or(WhereBase where, WhereBase whereA, WhereBase whereB) 112 //{ 113 // where.Instance = NHibernate.Expression.Expression.Or(whereA.Instance, whereB.Instance); 114 //} 115 //public static void Sql(WhereBase where, string sql) 116 //{ 117 // where.Instance = NHibernate.Expression.Expression.Sql(sql); 118 //} 119 #endregion 120 } 121 }
最好注释也去掉,这样的好处是别人开发的可以不管ORM是用什么第三方框架,直接调用WhereBase静态方法(代理模式)
WhereBase直接携带了Castle的搜索接口ICriterion,
在RepositoryBase有个这么个方法转换IWhere为Castle的搜索对象
1 #region 其他方法 2 NHibernate.Expression.ICriterion[] IWhere2ICriterion(IWhere[] where) 3 { 4 if (where == null) { 5 return null; 6 } 7 NHibernate.Expression.ICriterion[] wheres = new NHibernate.Expression.ICriterion[where.Length]; 8 for (var i = 0; i < where.Length; i++) 9 { 10 wheres[i] = (where[i] as WhereBase).Instance; 11 } 12 return wheres; 13 } 14 #endregion
这样就可以完美地实现搜索和排序的解耦
仓储基类有个方法实现如下:
1 public IEnumerable<T> FindAll<T>(IWhere[] where) where T : IEntity 2 { 3 if (where == null) { 4 return FindAll<T>(); 5 } 6 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(IWhere2ICriterion(where)); 7 }
三、总结:
1:搜索和排序的解耦不算是个难题
2: 实现的仓储基类可以通过IoC注入实例化,这样可以插拔式更换ORM
3: 定义的仓储接口和实现最好放在不同的类库,以更好的解耦
四、后记:Repository实现仓储--Castle实现
1 namespace Yom.NFramework2_0.CastleExtend 2 { 3 public abstract class EntityBase : Castle.ActiveRecord.ActiveRecordBase, Yom.NFramework2_0.IEntity 4 { 5 } 6 }
实体基类嫁接
1 namespace Yom.NFramework2_0 2 { 3 public interface ISinglePrimaryKeyRepository : IRepository<string> 4 { 5 } 6 }
非组合主键仓储扩展
1 namespace Yom.NFramework2_0.CastleExtend 2 { 3 public class CastleSinglePrimaryKeyRepository : ISinglePrimaryKeyRepository//, System.Configuration.IConfigurationSectionHandler 4 { 5 #region IRepository<string> 成员 6 7 #region 实体相关操作 8 public T FindBy<T>(string primaryKey) where T : IEntity 9 { 10 return Castle.ActiveRecord.ActiveRecordBase<T>.Find(primaryKey); 11 } 12 13 public IEnumerable<T> FindAll<T>() where T : IEntity 14 { 15 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(); 16 } 17 18 public IEnumerable<T> FindAll<T>(IWhere[] where) where T : IEntity 19 { 20 if (where == null) { 21 return FindAll<T>(); 22 } 23 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(IWhere2ICriterion(where)); 24 } 25 26 public IEnumerable<T> FindAll<T>(IWhere[] where, IOrder[] order) where T : IEntity 27 { 28 if (order == null) 29 { 30 if (where == null) 31 { 32 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(); 33 } 34 else 35 { 36 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(IWhere2ICriterion(where)); 37 } 38 } 39 else if (where == null) 40 { 41 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(order as NHibernate.Expression.Order[]); 42 } 43 44 return Castle.ActiveRecord.ActiveRecordBase<T>.FindAll(order as NHibernate.Expression.Order[], IWhere2ICriterion(where)); 45 } 46 47 public IEnumerable<T> FindAll<T>(int pageIndex, int pageSize, IWhere[] where, IOrder[] order, out int count) where T : IEntity 48 { 49 if (where == null) 50 { 51 count = Castle.ActiveRecord.ActiveRecordMediator.Count(typeof(T)); 52 if (order == null) { 53 return Castle.ActiveRecord.ActiveRecordBase<T>.SlicedFindAll(pageIndex * pageSize, pageSize); 54 55 }else{ 56 return Castle.ActiveRecord.ActiveRecordBase<T>.SlicedFindAll(pageIndex * pageSize, pageSize, order as NHibernate.Expression.Order[]); 57 } 58 } 59 else 60 { 61 count = Castle.ActiveRecord.ActiveRecordMediator.Count(typeof(T), IWhere2ICriterion(where)); 62 if (order == null) { 63 return Castle.ActiveRecord.ActiveRecordBase<T>.SlicedFindAll(pageIndex * pageSize, pageSize, IWhere2ICriterion(where)); 64 } 65 } 66 return Castle.ActiveRecord.ActiveRecordBase<T>.SlicedFindAll(pageIndex * pageSize, pageSize, order as NHibernate.Expression.Order[], IWhere2ICriterion(where)); 67 } 68 69 public void Add<T>(T entity) where T : IEntity 70 { 71 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 72 { 73 (entity as Castle.ActiveRecord.ActiveRecordBase).CreateAndFlush(); 74 tran.VoteCommit(); 75 } 76 } 77 78 public void Delete<T>(T entity) where T : IEntity 79 { 80 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 81 { 82 (entity as Castle.ActiveRecord.ActiveRecordBase).DeleteAndFlush(); 83 tran.VoteCommit(); 84 } 85 } 86 87 public void DeleteAll<T>() where T : IEntity 88 { 89 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 90 { 91 Castle.ActiveRecord.ActiveRecordBase<T>.DeleteAll(); 92 tran.VoteCommit(); 93 } 94 } 95 96 public void DeleteAll<T>(IWhere[] where) where T : IEntity 97 { 98 IEnumerable<T> entities; 99 if (where == null) 100 { 101 entities = this.FindAll<T>(); 102 } 103 else 104 { 105 entities = this.FindAll<T>(where); 106 } 107 if (entities != null) 108 { 109 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 110 { 111 foreach (T entity in entities) { 112 this.Delete<T>(entity); 113 } 114 tran.VoteCommit(); 115 } 116 } 117 } 118 public void DeleteAll<T>(string where) where T : IEntity 119 { 120 121 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 122 { 123 Castle.ActiveRecord.ActiveRecordBase<T>.DeleteAll(where); 124 tran.VoteCommit(); 125 } 126 127 } 128 public void DeleteAll<T>(IEnumerable<string> pkValues) where T : IEntity 129 { 130 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 131 { 132 Castle.ActiveRecord.ActiveRecordBase<T>.DeleteAll(pkValues); 133 tran.VoteCommit(); 134 } 135 } 136 137 public void Update<T>(T entity) where T : IEntity 138 { 139 using (Castle.ActiveRecord.TransactionScope tran = new Castle.ActiveRecord.TransactionScope()) 140 { 141 (entity as Castle.ActiveRecord.ActiveRecordBase).UpdateAndFlush(); 142 tran.VoteCommit(); 143 } 144 } 145 146 public bool Exists<T>(string primaryKey) where T : IEntity 147 { 148 return Castle.ActiveRecord.ActiveRecordBase<T>.Exists<string>(primaryKey); 149 } 150 #endregion 151 #region ado执行sql 152 public int ExecuteSql(string sql, params System.Data.IDataParameter[] ps) 153 { 154 using (System.Data.IDbCommand cmd = Castle.ActiveRecord.ActiveRecordMediator.GetSessionFactoryHolder().CreateSession(typeof(CastleSinglePrimaryKeyRepository)).Connection.CreateCommand()) 155 { 156 cmd.CommandText = sql; 157 if (ps != null && ps.Length > 0) 158 { 159 foreach (System.Data.IDataParameter p in ps) 160 { 161 cmd.Parameters.Add(p); 162 } 163 } 164 return cmd.ExecuteNonQuery(); 165 } 166 } 167 168 public object ExecuteScalar(string sql, params System.Data.IDataParameter[] ps) 169 { 170 using (System.Data.IDbCommand cmd = Castle.ActiveRecord.ActiveRecordMediator.GetSessionFactoryHolder().CreateSession(typeof(CastleSinglePrimaryKeyRepository)).Connection.CreateCommand()) 171 { 172 cmd.CommandText = sql; 173 if (ps != null && ps.Length > 0) 174 { 175 foreach (System.Data.IDataParameter p in ps) 176 { 177 cmd.Parameters.Add(p); 178 } 179 } 180 return cmd.ExecuteScalar(); 181 } 182 } 183 184 public System.Data.DataTable ExecuteDataTable(string sql, params System.Data.IDataParameter[] ps) 185 { 186 using (System.Data.IDbCommand cmd = Castle.ActiveRecord.ActiveRecordMediator.GetSessionFactoryHolder().CreateSession(typeof(CastleSinglePrimaryKeyRepository)).Connection.CreateCommand()) 187 { 188 cmd.CommandText = sql; 189 if (ps != null && ps.Length > 0) 190 { 191 foreach (System.Data.IDataParameter p in ps) 192 { 193 cmd.Parameters.Add(p); 194 } 195 } 196 System.Data.DataTable result = new System.Data.DataTable(); 197 result.Load(cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection)); 198 return result; 199 } 200 } 201 #endregion 202 #endregion 203 #region 其他方法 204 NHibernate.Expression.ICriterion[] IWhere2ICriterion(IWhere[] where) 205 { 206 if (where == null) { 207 return null; 208 } 209 NHibernate.Expression.ICriterion[] wheres = new NHibernate.Expression.ICriterion[where.Length]; 210 for (var i = 0; i < where.Length; i++) 211 { 212 wheres[i] = (where[i] as WhereBase).Instance; 213 } 214 return wheres; 215 } 216 #endregion 217 } 218 }
Castle实现IReposoitory
五、项目开发的层次结构