1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.ActiveRecord
.Framework
.Scopes
18 using System
.Collections
.Generic
;
24 /// Still very experimental and it's not bullet proof
25 /// for all situations
27 public class DifferentDatabaseScope
: AbstractScope
29 private readonly IDbConnection connection
;
30 private readonly SessionScope parentSimpleScope
;
31 private readonly TransactionScope parentTransactionScope
;
34 /// Initializes a new instance of the <see cref="DifferentDatabaseScope"/> class.
36 /// <param name="connection">The connection.</param>
37 public DifferentDatabaseScope(IDbConnection connection
) : this(connection
, FlushAction
.Auto
)
42 /// Initializes a new instance of the <see cref="DifferentDatabaseScope"/> class.
44 /// <param name="connection">The connection.</param>
45 /// <param name="flushAction">The flush action.</param>
46 public DifferentDatabaseScope(IDbConnection connection
, FlushAction flushAction
) : base(flushAction
, SessionScopeType
.Custom
)
48 if (connection
== null) throw new ArgumentNullException("connection");
50 this.connection
= connection
;
52 ISessionScope parentScope
= ScopeUtil
.FindPreviousScope(this, true);
54 if (parentScope
!= null)
56 if (parentScope
.ScopeType
== SessionScopeType
.Simple
)
58 parentSimpleScope
= (SessionScope
) parentScope
;
60 else if (parentScope
.ScopeType
== SessionScopeType
.Transactional
)
62 parentTransactionScope
= (TransactionScope
) parentScope
;
64 parentTransactionScope
.OnTransactionCompleted
+= OnTransactionCompleted
;
74 /// We want to be in charge of creating the session
77 public override bool WantsToCreateTheSession
83 /// This method is invoked when no session was available
84 /// at and the <see cref="Castle.ActiveRecord.Framework.ISessionFactoryHolder"/>
85 /// just created one. So it registers the session created
86 /// within this scope using a key. The scope implementation
87 /// shouldn't make any assumption on what the key
88 /// actually is as we reserve the right to change it
89 /// <seealso cref="IsKeyKnown"/>
91 /// <param name="key">an object instance</param>
92 /// <param name="session">An instance of <c>ISession</c></param>
93 public override void RegisterSession(object key
, ISession session
)
95 if (parentTransactionScope
!= null)
97 // parentTransactionalScope.EnsureHasTransaction(session);
98 parentTransactionScope
.RegisterSession(new KeyHolder(key
, connection
.ConnectionString
), session
);
100 else if (parentSimpleScope
!= null)
102 parentSimpleScope
.RegisterSession(new KeyHolder(key
, connection
.ConnectionString
), session
);
105 base.RegisterSession(key
, session
);
109 /// This method is invoked when the
110 /// <see cref="Castle.ActiveRecord.Framework.ISessionFactoryHolder"/>
111 /// instance needs a session instance. Instead of creating one it interrogates
112 /// the active scope for one. The scope implementation must check if it
113 /// has a session registered for the given key.
114 /// <seealso cref="RegisterSession"/>
116 /// <param name="key">an object instance</param>
118 /// <c>true</c> if the key exists within this scope instance
120 public override bool IsKeyKnown(object key
)
122 if (parentTransactionScope
!= null)
124 return parentTransactionScope
.IsKeyKnown(new KeyHolder(key
, connection
.ConnectionString
));
127 bool keyKnown
= false;
129 if (parentSimpleScope
!= null)
131 keyKnown
= parentSimpleScope
.IsKeyKnown(new KeyHolder(key
, connection
.ConnectionString
));
134 return keyKnown
? true : base.IsKeyKnown(key
);
138 /// This method should return the session instance associated with the key.
140 /// <param name="key">an object instance</param>
142 /// the session instance or null if none was found
144 public override ISession
GetSession(object key
)
146 if (parentTransactionScope
!= null)
148 return parentTransactionScope
.GetSession(new KeyHolder(key
, connection
.ConnectionString
));
151 ISession session
= null;
153 if (parentSimpleScope
!= null)
155 session
= parentSimpleScope
.GetSession(new KeyHolder(key
, connection
.ConnectionString
));
158 session
= session
?? base.GetSession(key
);
164 /// Performs the disposal.
166 /// <param name="sessions">The sessions.</param>
167 protected override void PerformDisposal(ICollection
<ISession
> sessions
)
169 if (parentTransactionScope
== null && parentSimpleScope
== null)
171 PerformDisposal(sessions
, true, true);
176 /// If the <see cref="WantsToCreateTheSession"/> returned
177 /// <c>true</c> then this method is invoked to allow
178 /// the scope to create a properly configured session
180 /// <param name="sessionFactory">From where to open the session</param>
181 /// <param name="interceptor">the NHibernate interceptor</param>
182 /// <returns>the newly created session</returns>
183 public override ISession
OpenSession(ISessionFactory sessionFactory
, IInterceptor interceptor
)
185 return sessionFactory
.OpenSession(connection
, interceptor
);
189 /// This is called when a session has a failure
191 /// <param name="session">the session</param>
192 public override void FailSession(ISession session
)
194 if (parentTransactionScope
!= null)
196 parentTransactionScope
.VoteRollBack();
204 private void OnTransactionCompleted(object sender
, EventArgs e
)
206 TransactionScope scope
= (sender
as TransactionScope
);
207 scope
.DiscardSessions( GetSessions() );
213 private readonly object inner
;
214 private readonly String connectionString
;
216 public KeyHolder(object inner
, String connectionString
)
219 this.connectionString
= connectionString
;
222 public override bool Equals(object obj
)
224 KeyHolder other
= obj
as KeyHolder
;
228 return ReferenceEquals(inner
, other
.inner
) &&
229 connectionString
== other
.connectionString
;
235 public override int GetHashCode()
237 return inner
.GetHashCode() ^ connectionString
.GetHashCode();