66
77using System ;
88using System . Collections . Generic ;
9+ using System . Data . Common ;
910using System . Threading ;
1011using System . Threading . Tasks ;
1112using System . Transactions ;
@@ -28,12 +29,7 @@ public sealed partial class Transaction : IHasExtensions
2829 /// Gets the current <see cref="Transaction"/> object
2930 /// using <see cref="Session"/>.<see cref="Orm.Session.Current"/>.
3031 /// </summary>
31- public static Transaction Current {
32- get {
33- var session = Session . Current ;
34- return session ? . Transaction ;
35- }
36- }
32+ public static Transaction Current => Session . Current ? . Transaction ;
3733
3834 /// <summary>
3935 /// Gets the current <see cref="Transaction"/>,
@@ -44,16 +40,8 @@ public static Transaction Current {
4440 /// <exception cref="InvalidOperationException">
4541 /// <see cref="Transaction.Current"/> <see cref="Transaction"/> is <see langword="null" />.
4642 /// </exception>
47- public static Transaction Demand ( )
48- {
49- var current = Current ;
50- if ( current == null ) {
51- throw new InvalidOperationException (
52- Strings . ExActiveTransactionIsRequiredForThisOperationUseSessionOpenTransactionToOpenIt ) ;
53- }
54-
55- return current ;
56- }
43+ public static Transaction Demand ( ) =>
44+ Current ?? throw new InvalidOperationException ( Strings . ExActiveTransactionIsRequiredForThisOperationUseSessionOpenTransactionToOpenIt ) ;
5745
5846 /// <summary>
5947 /// Checks whether a transaction exists or not in the provided session.
@@ -68,58 +56,70 @@ public static void Require(Session session)
6856
6957 #endregion
7058
71- private readonly List < StateLifetimeToken > lifetimeTokens ;
59+ private readonly List < StateLifetimeToken > lifetimeTokens = new ( 1 ) ;
7260
7361 private ExtensionCollection extensions ;
7462 private Transaction inner ;
7563
7664 /// <summary>
7765 /// Gets a value indicating whether this instance is automatic transaction.
7866 /// </summary>
79- public bool IsAutomatic { get ; private set ; }
80-
67+ public bool IsAutomatic { get ; }
68+
8169 /// <summary>
8270 /// Gets a value indicating whether this instance is
8371 /// transaction running locally.
8472 /// </summary>
85- public bool IsDisconnected { get ; private set ; }
86-
73+ public bool IsDisconnected { get ; }
74+
75+ private Guid ? guid ;
8776 /// <summary>
8877 /// Gets the unique identifier of this transaction.
8978 /// Nested transactions have the same <see cref="Guid"/>
9079 /// as their outermost.
9180 /// </summary>
92- public Guid Guid { get ; private set ; }
81+ public Guid Guid => Outer ? . Guid ?? ( guid ??= Guid . NewGuid ( ) ) ;
9382
9483 /// <summary>
9584 /// Gets the session this transaction is bound to.
9685 /// </summary>
97- public Session Session { get ; private set ; }
86+ public Session Session { get ; }
9887
9988 /// <summary>
10089 /// Gets the isolation level.
10190 /// </summary>
102- public IsolationLevel IsolationLevel { get ; private set ; }
91+ public IsolationLevel IsolationLevel { get ; }
10392
10493 /// <summary>
10594 /// Gets the state of the transaction.
10695 /// </summary>
107- public TransactionState State { get ; private set ; }
96+ public TransactionState State { get ; private set ; } = TransactionState . NotActivated ;
10897
10998 /// <summary>
11099 /// Gets the outer transaction.
111100 /// </summary>
112- public Transaction Outer { get ; private set ; }
101+ public Transaction Outer { get ; }
113102
114103 /// <summary>
115104 /// Gets the outermost transaction.
116105 /// </summary>
117- public Transaction Outermost { get ; private set ; }
106+ public Transaction Outermost => Outer ? . Outermost ?? this ;
118107
119108 /// <summary>
120109 /// Gets the start time of this transaction.
121110 /// </summary>
122- public DateTime TimeStamp { get ; private set ; }
111+ public DateTime TimeStamp { get ; } = DateTime . UtcNow ;
112+
113+ private TimeSpan ? timeout ;
114+ /// <summary>
115+ /// Gets or sets Transaction timeout
116+ /// </summary>
117+ public TimeSpan ? Timeout {
118+ get => timeout ;
119+ set => timeout = IsNested
120+ ? throw new InvalidOperationException ( Strings . ExNestedTransactionTimeout )
121+ : value ;
122+ }
123123
124124 /// <summary>
125125 /// Gets a value indicating whether this transaction is a nested transaction.
@@ -129,7 +129,7 @@ public static void Require(Session session)
129129 /// <summary>
130130 /// Gets <see cref="StateLifetimeToken"/> associated with this transaction.
131131 /// </summary>
132- public StateLifetimeToken LifetimeToken { get ; private set ; }
132+ public StateLifetimeToken LifetimeToken { get ; private set ; } = new ( ) ;
133133
134134 #region IHasExtensions Members
135135
@@ -138,7 +138,7 @@ public static void Require(Session session)
138138
139139 #endregion
140140
141- internal string SavepointName { get ; private set ; }
141+ internal string SavepointName { get ; }
142142
143143 /// <summary>
144144 /// Indicates whether changes made in this transaction are visible "as is"
@@ -278,40 +278,34 @@ private void ClearLifetimeTokens()
278278 LifetimeToken = null ;
279279 }
280280
281+ internal void CheckForTimeout ( DbCommand command )
282+ {
283+ if ( Timeout is not null ) {
284+ var remain = TimeStamp + Timeout . Value - DateTime . UtcNow ;
285+ command . CommandTimeout = remain . Ticks > 0
286+ ? Math . Max ( 1 , ( int ) remain . TotalSeconds )
287+ : throw new TimeoutException ( String . Format ( Strings . ExTransactionTimeout , Timeout ) ) ;
288+ }
289+ }
290+
281291 #endregion
282292
283-
284- // Constructors
285293
286- internal Transaction ( Session session , IsolationLevel isolationLevel , bool isAutomatic )
287- : this ( session , isolationLevel , isAutomatic , null , null )
288- {
289- }
294+ // Constructors
290295
291- internal Transaction ( Session session , IsolationLevel isolationLevel , bool isAutomatic , Transaction outer ,
292- string savepointName )
296+ internal Transaction ( Session session , IsolationLevel isolationLevel , bool isAutomatic , Transaction outer = null ,
297+ string savepointName = null )
293298 {
294- lifetimeTokens = new List < StateLifetimeToken > ( ) ;
295-
296- Guid = Guid . NewGuid ( ) ;
297- State = TransactionState . NotActivated ;
298299 Session = session ;
299300 IsolationLevel = isolationLevel ;
300301 IsAutomatic = isAutomatic ;
301302 IsDisconnected = session . IsDisconnected ;
302- TimeStamp = DateTime . UtcNow ;
303- LifetimeToken = new StateLifetimeToken ( ) ;
304303 lifetimeTokens . Add ( LifetimeToken ) ;
305304
306305 if ( outer != null ) {
307306 Outer = outer ;
308- Guid = outer . Guid ;
309- Outermost = outer . Outermost ;
310307 SavepointName = savepointName ;
311308 }
312- else {
313- Outermost = this ;
314- }
315309 }
316310 }
317- }
311+ }
0 commit comments