tobinharris (owner)

Revisions

gist: 108433 Download_button fork
public
Public Clone URL: git://gist.github.com/108433.git
Embed All Files: show embed
UoW.cs #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
using System;
using System.Collections.Generic;
using System.IO;
using FluentNHibernate;
using FluentNHibernate.AutoMap;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Context;
using NHibernate.Event;
using Portal.Core.Application.DataAccess;
 
namespace Portal.Core.Infrastructure.DataAccess
{
/// <summary>
/// Simple NHibernate Unit Of Work class that will work in ASP.NET and Unit Tests.
///
/// Usage:
///
/// GLOBAL.ASCX.CS
///
/// void Application_Start(object sender, EventArgs e)
/// {
/// UoW.Configure("server=local;catalog=test;");
/// }
///
/// void Application_BeginRequest(object sender, EventArgs e)
/// {
/// UoW.Start();
/// }
///
/// void Application_EndRequest(object sender, EventArgs e)
/// {
        /// if(UoW.IsStarted)
/// UoW.End();
/// }
///
/// </summary>
public static class UoW
{
#region Environment enum
 
/// <summary>
/// What environment do we want to run? Web or Other (suitable for unit tests, desktop clients or remoting)
/// </summary>
public enum Environment
{
Web,
Other,
Test
}
 
#endregion
 
/// <summary>
/// NHibernate session factory is expensive to create.
/// Therefore we keep it as a static variable so we only create it once.
/// It's thread safe, so static if fine for both web and desktop.
/// </summary>
private static ISessionFactory _nhibernateSessionFactory;
 
/// <summary>
/// We stash the configuration here just to be helpful, in case the app needs it.
/// This is optional really.
/// </summary>
public static Configuration NHibernateConfiguration { get; private set; }
 
/// <summary>
/// Get the session. You must Start the Unit of Work before calling this.
/// </summary>
public static ISession Session
{
get { return _nhibernateSessionFactory.GetCurrentSession(); }
}
 
        public static bool IsStarted
        {
            get
            {
if (_nhibernateSessionFactory == null) return false;
                return CurrentSessionContext.HasBind(_nhibernateSessionFactory);
            }
        }
 
 
/// <summary>
/// Get the session factory. Can be accessed once has be created.
/// </summary>
public static ISessionFactory SessionFactory
{
get { return _nhibernateSessionFactory; }
}
 
/// <summary>
/// Constructor. We'd only create One UoW class for the entire application (one per ASP.NET App Pool)
/// </summary>
/// <param name="nhibernateConfiguration"></param>
public static void Configure(Configuration nhibernateConfiguration)
{
NHibernateConfiguration = nhibernateConfiguration;
_nhibernateSessionFactory = nhibernateConfiguration.BuildSessionFactory();
}
 
public static Configuration Configure(string connectionString, Environment env)
{
return Configure(connectionString, env, x => {});
}
        
/// <summary>
/// Simpler constructor. We'd only create One UoW class for the entire application (one per ASP.NET App Pool)
/// </summary>
/// <param name="connectionString"></param>
/// <param name="env">Where will this UoW be used? Web? </param>
public static Configuration Configure(string connectionString, Environment env, Action<Configuration> configurationAction)
{
NHibernateConfiguration = new Configuration();
 
//we will poke some additional properties into the config
var additionalProperties = new Dictionary<string, string>();
 
 
//the first is the session context. This allows NHibernate to take care of where it's being used.
//See NHibernate in Action page 327
if (env == Environment.Web)
{
additionalProperties.Add("current_session_context_class", typeof (WebSessionContext).FullName);
}
else
additionalProperties.Add("current_session_context_class", typeof(CallSessionContext).FullName);
 
            additionalProperties.Add("use_proxy_validator", "false");
 
//additionalProperties.Add("query.substitutions", "true 1, false 0, True 1, False 0, yes 'Y', no 'N', bw_or ^, bw_and &, bw_not ~");
 
AutoPersistenceModel mappings = MyMappings.Create();
 
if (env == Environment.Test && string.IsNullOrEmpty(connectionString))
{
SQLiteConfiguration
.Standard
.InMemory()
.QuerySubstitutions("true 1, false 0, True 1, False 0, yes 'Y', no 'N', bw_or ^, bw_and &, bw_not ~")
//.UsingFile("test.db")
.ShowSql()
.ConfigureProperties(NHibernateConfiguration)
.AddProperties(additionalProperties)
.AddAutoMappings(mappings)
                    
                    
//.SetListener(ListenerType.FlushEntity, new CustomSaveEventListener())
;
// if(Directory.Exists("c:\\Mappings"))
// mappings.WriteMappingsTo("c:\\Mappings\\");
// else
// Console.Write("Not dumping mappings to file for preview because no c:\\Mappings folder.");
 
}
else
{
//use Fluent to fluently configure the database
//you'd have to change this if using MySQL for example.
MsSqlConfiguration
.MsSql2005
.ConnectionString(c => c.Is(connectionString))
.QuerySubstitutions("true 1, false 0, True 1, False 0, yes 'Y', no 'N', bw_or ^, bw_and &, bw_not ~")
.ShowSql()
.ConfigureProperties(NHibernateConfiguration)
.AddProperties(additionalProperties)
.AddAutoMappings(mappings)
.SetProperty("generate_statistics", "true")
.SetListener(ListenerType.FlushEntity, new CustomSaveEventListener())
;
}
 
            NHibernateConfiguration.SetListener(ListenerType.Update, new CustomUpdateEventListener());
            NHibernateConfiguration.SetListener(ListenerType.SaveUpdate, new CustomSaveOrUpdateEventListener());
 
 
configurationAction.Invoke(NHibernateConfiguration);
 
//set the static session factory (that will live for as long as the AppPool does
_nhibernateSessionFactory = NHibernateConfiguration.BuildSessionFactory();
 
return NHibernateConfiguration;
}
        
/// <summary>
/// Start a new unit of work.
/// </summary>
public static void Start()
{
if(_nhibernateSessionFactory == null) return;
//stash a new session where we can get at it at any time. NHibernate already
//has a CurrentSessionContext class for keeping sessions somewhere accessible.
CurrentSessionContext.Bind(_nhibernateSessionFactory.OpenSession());
 
//We don't want to push any work to the DB unless we explicitly call Commit.
Session.FlushMode = FlushMode.Commit;
 
//all our work should be in a transaction
Session.BeginTransaction();
}
 
/// <summary>
/// Send all work done in the UoW's transaction to the database. Also starts a new transaction
/// ready for any additional work you do.
/// You can call this method multiple times for during a single Unit of Work
/// if you want to send several updates separately.
/// </summary>
public static void Commit()
{
Session.Transaction.Commit();
Session.BeginTransaction();
}
 
/// <summary>
/// End the current unit of work.
/// </summary>
public static void End()
{
//We want to roll back any active transaction. If the user of this class wanted to commit
//any updates then he should have to have called UoW.Commit().
if (Session.Transaction != null && Session.Transaction.IsActive) Session.Transaction.Rollback();
 
//close the session
Session.Close();
 
//Session is disposable, and therefor it's good to call Dispose() once we're done with it.
Session.Dispose();
 
//unbind the session from the context as we won't be needing it.
CurrentSessionContext.Unbind(_nhibernateSessionFactory);
}
}
}