經過了上篇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
五、項目開發的層次結構