For several of my projects I use a repository pattern for the data access layer which sits above Fluent NHibernate. Using generics I can then replicate the same features for all entity repositories.
An example of the base interface is shown below.
1: /// <summary>
2: /// Base repository for nhibernate
3: /// </summary>
4: /// <typeparam name="T">Entity</typeparam>
5: public interface INHibernateBaseRepository<T>
6: { 7: /// <summary>
8: /// Gets the current session in the repository
9: /// </summary>
10: /// <returns>Current session</returns>
11: ISession GetCurrentSession(); 12: 13: /// <summary>
14: /// Finds an entity by passed identifier
15: /// </summary>
16: /// <param name="id">Identifier</param>
17: /// <returns>Entity matching identifier</returns>
18: T FindById(long id);
19: 20: /// <summary>
21: /// Saves entity
22: /// </summary>
23: /// <param name="t">Entity to save</param>
24: void Save(T t);
25: 26: /// <summary>
27: /// Saves or updates entity
28: /// </summary>
29: /// <param name="t">Entity to save or update</param>
30: T SaveOrUpdate(T t); 31: 32: /// <summary>
33: /// Deletes entity
34: /// </summary>
35: /// <param name="t">Entity to delete</param>
36: void Delete(T t);
37: 38: /// <summary>
39: /// Finds all entities and passes back as a collection
40: /// </summary>
41: /// <returns>Collection of entities</returns>
42: IList<T> FindAll(); 43: 44: /// <summary>
45: /// Finds all entities by passed order and passes back as a collection
46: /// </summary>
47: /// <param name="orders">Orders</param>
48: /// <returns>Collection of entities</returns>
49: IList<T> FindAll(params Order[] orders);
50: 51: /// <summary>
52: /// Finds all entities and passes back as a collection within the range specified
53: /// </summary>
54: /// <param name="firstResult">First result</param>
55: /// <param name="numberOfResults">Number of results to return</param>
56: /// <returns>Collection of entities</returns>
57: IList<T> FindAll(int firstResult, int numberOfResults);
58: 59: /// <summary>
60: /// Finds all entities and passes back as a collection within the range specified
61: /// </summary>
62: /// <param name="firstResult">First result</param>
63: /// <param name="numberOfResults">Number of results to return</param>
64: /// <param name="orders">Orders</param>
65: /// <returns>Collection of entities</returns>
66: IList<T> FindAll(int firstResult, int numberOfResults, params Order[] orders);
67: 68: /// <summary>
69: /// Finds all entities and passes back as a collection within the range specified
70: /// </summary>
71: /// <param name="firstResult">First result</param>
72: /// <param name="numberOfResults">Number of results</param>
73: /// <param name="sortFields">Sort order dictionary</param>
74: /// <returns>List of entities</returns>
75: IList<T> FindAll(int firstResult, int numberOfResults, IDictionary<string, bool> sortFields);
76: 77: /// <summary>
78: /// Finds entities by criteria
79: /// </summary>
80: /// <param name="dc">Detatched criteria</param>
81: /// <returns>Collection of entities that match the passed criteria</returns>
82: IList<T> FindByCriteria(DetachedCriteria dc); 83: 84: /// <summary>
85: /// Finds entities by criteria and paging
86: /// </summary>
87: /// <param name="dc">Detatched criteria</param>
88: /// <param name="firstResult">First result</param>
89: /// <param name="numberOfResults">Number of results to return</param>
90: /// <returns>Collection of entities that match the passed criteria</returns>
91: IList<T> FindByCriteria(DetachedCriteria dc, int firstResult, int numberOfResults);
92: 93: /// <summary>
94: /// Finds entities by criteria, paging and ordering
95: /// </summary>
96: /// <param name="dc">Detatched criteria</param>
97: /// <param name="firstResult">First result</param>
98: /// <param name="numberOfResults">Number of results to return</param>
99: /// <param name="orders">Orders</param>
100: /// <returns>Collection of entities that match the passed criteria</returns>
101: IList<T> FindByCriteria(DetachedCriteria dc, int firstResult, int numberOfResults, params Order[] orders);
102: 103: /// <summary>
104: /// Gets a list of entities by passed query
105: /// </summary>
106: /// <param name="queryString">Query to get entities</param>
107: /// <returns>Collection of entities</returns>
108: IList<T> FindByQuery(string queryString);
109: 110: /// <summary>
111: /// Gets a list of entities by passed query and parameters
112: /// </summary>
113: /// <param name="queryString">Query to get entities</param>
114: /// <param name="parameters">Parameters to set in query</param>
115: /// <returns>Collection of entities</returns>
116: IList<T> FindByQuery(string queryString, params object[] parameters);
117: 118: /// <summary>
119: /// Gets a list of entities by passed query
120: /// </summary>
121: /// <param name="queryString">Query to get entities</param>
122: /// <param name="firstResult">First result</param>
123: /// <param name="numberOfResults">Number of results to return</param>
124: /// <returns>Collection of entities</returns>
125: IList<T> FindByQuery(string queryString, int firstResult, int numberOfResults);
126: 127: /// <summary>
128: /// Gets a list of entities by passed query and parameters
129: /// </summary>
130: /// <param name="queryString">Query to get entities</param>
131: /// <param name="firstResult">First result</param>
132: /// <param name="numberOfResults">Number of results to return</param>
133: /// <param name="parameters">Parameters to set in query</param>
134: /// <returns>Collection of entities</returns>
135: IList<T> FindByQuery(string queryString, int firstResult, int numberOfResults, params object[] parameters);
136: 137: /// <summary>
138: /// Finds one entity that matches criteria and throws exception otherwise
139: /// </summary>
140: /// <param name="criteria">Criteria</param>
141: /// <returns>Entity matching criteria</returns>
142: T FindOne(DetachedCriteria criteria); 143: 144: /// <summary>
145: /// Finds first entity in collection that matches criteria
146: /// </summary>
147: /// <param name="criteria">Criteria</param>
148: /// <returns>First entity</returns>
149: T FindFirst(DetachedCriteria criteria); 150: 151: /// <summary>
152: /// Finds first entity in collection that matches criteria and order params
153: /// </summary>
154: /// <param name="criteria">Criteria</param>
155: /// <param name="orders">Orders</param>
156: /// <returns>First entity</returns>
157: T FindFirst(DetachedCriteria criteria, params Order[] orders);
158: 159: /// <summary>
160: /// Get count of entities that match criteria
161: /// </summary>
162: /// <param name="criteria">Criteria</param>
163: /// <returns>Count of number of entities that match criteria</returns>
164: long Count(DetachedCriteria criteria);
165: 166: /// <summary>
167: /// Get count of entities
168: /// </summary>
169: /// <returns>Count of entities</returns>
170: long Count();
171: 172: /// <summary>
173: /// Determines if at least one entity exists that matches passed criteria
174: /// </summary>
175: /// <param name="criteria">Criteria</param>
176: /// <returns><c>true</c> if exists</returns>
177: bool Exists(DetachedCriteria criteria);
178: }Then a base class to implement this interface - as follows:
1: #region Usings
2: 3: using System;
4: using System.Collections.Generic;
5: using Castle.Facilities.NHibernateIntegration;
6: using AimKai.Core.Interfaces;
7: using AimKai.Core.Resources;
8: using AimKai.Core.Util;
9: using log4net;
10: using NHibernate;
11: using NHibernate.Criterion;
12: using System.Linq;
13: 14: #endregion Usings
15: 16: /// <summary>
17: /// Base nhibernate repository
18: /// </summary>
19: /// <typeparam name="T">Type</typeparam>
20: public abstract class NHibernateBaseRepository<T> : INHibernateBaseRepository<T>
21: { 22: #region Fields
23: 24: /// <summary>
25: /// Session manager
26: /// </summary>
27: protected readonly ISessionManager SessionManager;
28: 29: #endregion Fields
30: 31: #region Properties
32: 33: /// <summary>
34: /// Gets the current session
35: /// </summary>
36: public virtual ISession Session
37: { 38: get { return SessionManager.OpenSession(); }
39: } 40: 41: /// <summary>
42: /// Gets the base log here
43: /// </summary>
44: public ILog NHibernateBaseRepositoryLog = LogManager.GetLogger(typeof (NHibernateBaseRepository<T>));
45: 46: #endregion Properties
47: 48: #region Constructors
49: 50: /// <summary>
51: /// Set session manager via constructor
52: /// </summary>
53: /// <param name="sessionManager"></param>
54: protected NHibernateBaseRepository(ISessionManager sessionManager)
55: { 56: SessionManager = sessionManager; 57: } 58: 59: #endregion Constructors
60: 61: #region Public Methods
62: 63: #region INHibernateBaseRespository<T> Members
64: 65: /// <summary>
66: /// Gets the current session in the repository
67: /// </summary>
68: /// <returns>Current session</returns>
69: public ISession GetCurrentSession()
70: { 71: return Session;
72: } 73: 74: /// <summary>
75: /// Finds an entity by passed identifier
76: /// </summary>
77: /// <param name="id">Identifier</param>
78: /// <returns>Entity matching identifier</returns>
79: public T FindById(long id)
80: { 81: return Session.Get<T>(id);
82: } 83: 84: /// <summary>
85: /// Loads an entity by passed identifier
86: /// </summary>
87: /// <param name="id">Identifier</param>
88: /// <returns>Entity matching identifier</returns>
89: public T Load(long id)
90: { 91: return Session.Load<T>(id);
92: } 93: 94: /// <summary>
95: /// Saves entity
96: /// </summary>
97: /// <param name="t">Entity to save</param>
98: public void Save(T t)
99: { 100: //Use transaction here
101: using (var tx = Session.BeginTransaction())
102: { 103: try
104: { 105: //Check to see if we can validate
106: var validateMethod = t.GetType().GetMethod("Validate");
107: if (validateMethod != null)
108: validateMethod.Invoke(t, null);
109: 110: //Save here
111: Session.Save(t); 112: tx.Commit(); 113: } 114: catch (Exception ex)
115: { 116: tx.Rollback(); 117: 118: // throw not saved exception
119: NHibernateBaseRepositoryLog.Error(ex); 120: throw new CoreException("NHibernateBaseRepository_NotSaved", ExceptionMessages.NHibernateBaseRepository_NotSaved, ex,
121: new object[] {"Save", ex.Message});
122: } 123: } 124: } 125: 126: /// <summary>
127: /// Saves or updates entity
128: /// </summary>
129: /// <param name="t">Entity to save or update</param>
130: public T SaveOrUpdate(T t)
131: { 132: //Use transaction here
133: using (var tx = Session.BeginTransaction())
134: { 135: try
136: { 137: Session.SaveOrUpdate(t); 138: tx.Commit(); 139: } 140: catch (Exception ex)
141: { 142: tx.Rollback(); 143: 144: // throw not saved exception
145: NHibernateBaseRepositoryLog.Error(ex); 146: throw new CoreException("NHibernateBaseRepository_NotSaved",
147: ExceptionMessages.NHibernateBaseRepository_NotSaved, ex, 148: new object[] {"Save or Update", ex.Message});
149: } 150: } 151: return t;
152: } 153: 154: /// <summary>
155: /// Deletes entity
156: /// </summary>
157: /// <param name="t">Entity to delete</param>
158: public void Delete(T t)
159: { 160: using (var tx = Session.BeginTransaction())
161: { 162: try
163: { 164: Session.Delete(t); 165: tx.Commit(); 166: } 167: catch (Exception ex)
168: { 169: tx.Rollback(); 170: 171: // throw not saved exception
172: NHibernateBaseRepositoryLog.Error(ex); 173: throw new CoreException("NHibernateBaseRepository_NotSaved",
174: ExceptionMessages.NHibernateBaseRepository_NotSaved, ex, 175: new object[] { "Delete", ex.Message });
176: } 177: } 178: } 179: 180: /// <summary>
181: /// Finds all entities and passes back as a collection
182: /// </summary>
183: /// <returns>Collection of entities</returns>
184: public IList<T> FindAll()
185: { 186: //Builds a criteria to pull back a collection of all items that match this type
187: return Session.CreateCriteria(typeof(T)).List<T>();
188: } 189: 190: /// <summary>
191: /// Finds all entities by passed order and passes back as a collection
192: /// </summary>
193: /// <param name="orders">Orders</param>
194: /// <returns>Collection of entities</returns>
195: public IList<T> FindAll(params Order[] orders)
196: { 197: return AddOrders(Session.CreateCriteria(typeof(T))).List<T>();
198: } 199: 200: /// <summary>
201: /// Finds all entities and passes back as a collection within the range specified
202: /// </summary>
203: /// <param name="firstResult">First result</param>
204: /// <param name="numberOfResults">Number of results to return</param>
205: /// <returns>Collection of entities</returns>
206: public IList<T> FindAll(int firstResult, int numberOfResults)
207: { 208: return Session.CreateCriteria(typeof(T))
209: .SetFirstResult(firstResult) 210: .SetMaxResults(numberOfResults) 211: .List<T>(); 212: } 213: 214: /// <summary>
215: /// Finds all entities and passes back as a collection within the range specified
216: /// </summary>
217: /// <param name="firstResult">First result</param>
218: /// <param name="numberOfResults">Number of results to return</param>
219: /// <param name="orders">Orders</param>
220: /// <returns>Collection of entities</returns>
221: public IList<T> FindAll(int firstResult, int numberOfResults, params Order[] orders)
222: { 223: return AddOrders(Session.CreateCriteria(typeof(T)))
224: .SetMaxResults(numberOfResults) 225: .SetFirstResult(firstResult) 226: .List<T>(); 227: } 228: 229: /// <summary>
230: /// Finds all entities and passes back as a collection within the range specified
231: /// </summary>
232: /// <param name="firstResult">First result</param>
233: /// <param name="numberOfResults">Number of results</param>
234: /// <param name="sortFields">Sort order dictionary</param>
235: /// <returns>Collection of entities</returns>
236: public IList<T> FindAll(int firstResult, int numberOfResults, IDictionary<string, bool> sortFields)
237: { 238: var orders = new List<Order>();
239: foreach (var item in sortFields)
240: { 241: var item1 = item; 242: if (typeof(T).GetProperties().Where(x => x.Name == item1.Key).Count() == 0)
243: throw new CoreException("NHibernateBaseRepository_SortParameterNotValid",
244: ExceptionMessages.NHibernateBaseRepository_SortParameterNotValid, 245: new object[] { item1.Key });
246: orders.Add(new Order(item1.Key, item1.Value));
247: } 248: return AddOrders(Session.CreateCriteria(typeof(T)))
249: .SetMaxResults(numberOfResults) 250: .SetFirstResult(firstResult) 251: .List<T>(); 252: } 253: 254: /// <summary>
255: /// Finds entities by criteria
256: /// </summary>
257: /// <param name="dc">Detatched criteria</param>
258: /// <returns>Collection of entities that match the passed criteria</returns>
259: public IList<T> FindByCriteria(DetachedCriteria dc)
260: { 261: return dc.GetExecutableCriteria(Session).List<T>();
262: } 263: 264: /// <summary>
265: /// Finds entities by criteria and paging
266: /// </summary>
267: /// <param name="dc">Detatched criteria</param>
268: /// <param name="firstResult">First result</param>
269: /// <param name="numberOfResults">Number of results to return</param>
270: /// <returns>Collection of entities that match the passed criteria</returns>
271: public IList<T> FindByCriteria(DetachedCriteria dc, int firstResult, int numberOfResults)
272: { 273: //Set paging
274: dc.SetFirstResult(firstResult).SetMaxResults(numberOfResults); 275: 276: //Execute criteria
277: return dc.GetExecutableCriteria(Session).List<T>();
278: } 279: 280: /// <summary>
281: /// Finds entities by criteria, paging and ordering
282: /// </summary>
283: /// <param name="dc">Detatched criteria</param>
284: /// <param name="firstResult">First result</param>
285: /// <param name="numberOfResults">Number of results to return</param>
286: /// <param name="orders">Orders</param>
287: /// <returns>Collection of entities that match the passed criteria</returns>
288: public IList<T> FindByCriteria(DetachedCriteria dc, int firstResult, int numberOfResults, params Order[] orders)
289: { 290: return AddOrders(dc, orders).SetFirstResult(firstResult).SetMaxResults(numberOfResults)
291: .GetExecutableCriteria(Session).List<T>(); 292: } 293: 294: /// <summary>
295: /// Gets a list of entities by passed query
296: /// </summary>
297: /// <param name="queryString">Query to get entities</param>
298: /// <returns>Collection of entities</returns>
299: public IList<T> FindByQuery(string queryString)
300: { 301: return Session.CreateQuery(queryString).List<T>();
302: } 303: 304: /// <summary>
305: /// Gets a list of entities by passed query and parameters
306: /// </summary>
307: /// <param name="queryString">Query to get entities</param>
308: /// <param name="parameters">Parameters to set in query</param>
309: /// <returns>Collection of entities</returns>
310: public IList<T> FindByQuery(string queryString, params object[] parameters)
311: { 312: var query = Session.CreateQuery(queryString); 313: if (parameters != null)
314: { 315: var count = 0; 316: foreach (var parameter in parameters)
317: { 318: query.SetParameter(count, parameter); 319: count++; 320: } 321: } 322: return query.List<T>();
323: } 324: 325: /// <summary>
326: /// Gets a list of entities by passed query
327: /// </summary>
328: /// <param name="queryString">Query to get entities</param>
329: /// <param name="firstResult">First result</param>
330: /// <param name="numberOfResults">Number of results to return</param>
331: /// <returns>Collection of entities</returns>
332: public IList<T> FindByQuery(string queryString, int firstResult, int numberOfResults)
333: { 334: return Session.CreateQuery(queryString)
335: .SetFirstResult(firstResult) 336: .SetMaxResults(numberOfResults) 337: .List<T>(); 338: } 339: 340: /// <summary>
341: /// Gets a list of entities by passed query and parameters
342: /// </summary>
343: /// <param name="queryString">Query to get entities</param>
344: /// <param name="firstResult">First result</param>
345: /// <param name="numberOfResults">Number of results to return</param>
346: /// <param name="parameters">Parameters to set in query</param>
347: /// <returns>Collection of entities</returns>
348: public IList<T> FindByQuery(string queryString, int firstResult, int numberOfResults, params object[] parameters)
349: { 350: var query = Session.CreateQuery(queryString); 351: if (parameters != null)
352: { 353: var count = 0; 354: foreach (var parameter in parameters)
355: { 356: query.SetParameter(count, parameter); 357: count++; 358: } 359: } 360: return query.List<T>();
361: } 362: 363: /// <summary>
364: /// Finds one entity that matches criteria and throws exception otherwise
365: /// </summary>
366: /// <param name="criteria">Criteria</param>
367: /// <returns>Entity matching criteria</returns>
368: public T FindOne(DetachedCriteria criteria)
369: { 370: return criteria.GetExecutableCriteria(Session).UniqueResult<T>();
371: } 372: 373: /// <summary>
374: /// Finds first entity in collection that matches criteria
375: /// </summary>
376: /// <param name="criteria">Criteria</param>
377: /// <returns>First entity</returns>
378: public T FindFirst(DetachedCriteria criteria)
379: { 380: //Do we have any results?
381: var results = criteria.SetMaxResults(1) 382: .GetExecutableCriteria(Session).List<T>(); 383: 384: return (results.Count > 0) ? results[0] : default(T);
385: } 386: 387: /// <summary>
388: /// Finds first entity in collection that matches criteria and order params
389: /// <remarks>Can be used to get last in a collection</remarks>
390: /// </summary>
391: /// <param name="criteria">Criteria</param>
392: /// <param name="orders">Orders</param>
393: /// <returns>First entity</returns>
394: public T FindFirst(DetachedCriteria criteria, params Order[] orders)
395: { 396: var results = AddOrders(criteria, orders).SetMaxResults(1) 397: .GetExecutableCriteria(Session).List<T>(); 398: 399: return (results.Count > 0) ? results[0] : default(T);
400: } 401: 402: /// <summary>
403: /// Get count of entities that match criteria
404: /// </summary>
405: /// <param name="criteria">Criteria</param>
406: /// <returns>Count of number of entities that match criteria</returns>
407: public long Count(DetachedCriteria criteria)
408: { 409: return Convert.ToInt64(criteria.GetExecutableCriteria(Session)
410: .SetProjection(Projections.RowCountInt64()).UniqueResult()); 411: } 412: 413: /// <summary>
414: /// Get count of entities
415: /// </summary>
416: /// <returns>Count of entities</returns>
417: public long Count()
418: { 419: return Convert.ToInt64(Session.CreateCriteria(typeof(T)).SetProjection(Projections.RowCountInt64()).UniqueResult());
420: } 421: 422: /// <summary>
423: /// Determines if at least one entity exists that matches passed criteria
424: /// </summary>
425: /// <param name="criteria">Criteria</param>
426: /// <returns><c>true</c> if exists</returns>
427: public bool Exists(DetachedCriteria criteria)
428: { 429: return Count(criteria) > 0;
430: } 431: 432: #endregion INHibernateBaseRespository<T> Members
433: 434: #endregion Public Methods
435: 436: #region Private Methods
437: 438: /// <summary>
439: /// Adds orders to detached criteria
440: /// </summary>
441: /// <param name="dc">Detached criteria</param>
442: /// <param name="orders">Orders</param>
443: /// <returns>Criteria with orders</returns>
444: private static DetachedCriteria AddOrders(DetachedCriteria dc, params Order[] orders)
445: { 446: //Build orders
447: if (orders != null)
448: foreach (var order in orders)
449: dc.AddOrder(order); 450: 451: return dc;
452: } 453: 454: /// <summary>
455: /// Adds orders to detached criteria
456: /// </summary>
457: /// <param name="dc">criteria</param>
458: /// <param name="orders">Orders</param>
459: /// <returns>Criteria with orders</returns>
460: private static ICriteria AddOrders(ICriteria dc, params Order[] orders)
461: { 462: //Build orders
463: if (orders != null)
464: foreach (var order in orders)
465: dc.AddOrder(order); 466: 467: return dc;
468: } 469: 470: #endregion Private Methods
471: }Then say if I have an entity called 'Mountain' I would name a repository 'MountainRepository' which implements the interface IMountainRepository:
1: /// <summary>
2: /// Provides Mountain repository functionality
3: /// </summary>
4: public interface IMountainRepository : INHibernateBaseRepository<Mountain>
5: { 6: /// <summary>
7: /// Get mountains by height
8: /// </summary>
9: /// <param name="height">Height of mountain</param>
10: IList<Mountain> GetMountainsByHeight(double height);
11: }and concrete implementation:
1: /// <summary>
2: /// Provides user group repository functionality
3: /// </summary>
4: public class MountainRepository: NHibernateBaseRepository<Mountain>, IMountainRepository
5: { 6: #region Constructors
7: 8: /// <summary>
9: /// Constructor for the suv user group restriction repository
10: /// </summary>
11: /// <param name="sessionManager">Session manager</param>
12: public SuvUserGroupRepository(ISessionManager sessionManager)
13: : base(sessionManager)
14: { 15: } 16: 17: #endregion Constructors
18: 19: #region Public Methods
20: 21: #region IMountainRepository Members
22: 23: /// <summary>
24: /// Get mountains by height
25: /// </summary>
26: /// <param name="height">Height of mountain</param>
27: public IList<Mountain> GetMountainsByHeight(double height)
28: { 29: return FindAll(DetachedCriteria.For<Mountain>().Add<Mountain>(x => x.Height == height));
30: } 31: 32: #endregion IMountainRepository Members
33: 34: #endregion Public Methods
35: }So the repository classes are all simpler and I have still access to the 20 odd base methods which have all the basic NHibernate functionality required.

No comments:
Post a Comment