Skip to content

Commit 31e8b81

Browse files
committed
Add configurable default command timeout
1 parent 55e636a commit 31e8b81

7 files changed

Lines changed: 194 additions & 17 deletions

File tree

src/FluentCommand/DataCommand.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,20 @@ public class DataCommand : DisposableBase, IDataCommand
2828
/// <param name="dataSession">The data session.</param>
2929
/// <param name="transaction">The DbTransaction for this DataCommand.</param>
3030
/// <param name="commandInterceptors">Pre-filtered command interceptors from the owning session.</param>
31+
/// <param name="commandTimeout">The command timeout in seconds.</param>
3132
public DataCommand(
3233
IDataSession dataSession,
3334
DbTransaction? transaction,
34-
IDataCommandInterceptor[]? commandInterceptors = null)
35+
IDataCommandInterceptor[]? commandInterceptors = null,
36+
int? commandTimeout = null)
3537
{
3638
_callbacks = new Queue<DataCallback>();
3739
_dataSession = dataSession ?? throw new ArgumentNullException(nameof(dataSession));
3840

3941
Command = dataSession.Connection.CreateCommand();
4042
Command.Transaction = transaction;
43+
if (commandTimeout.HasValue)
44+
Command.CommandTimeout = commandTimeout.Value;
4145

4246
_commandInterceptors = commandInterceptors ?? [];
4347
}

src/FluentCommand/DataConfiguration.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class DataConfiguration : IDataConfiguration
1818
/// <param name="cache">The data cache manager.</param>
1919
/// <param name="queryGenerator">The query generator.</param>
2020
/// <param name="queryLogger">The query command logger.</param>
21+
/// <param name="commandTimeout">The default command timeout in seconds.</param>
2122
/// <param name="interceptors">The interceptors to apply to each session created from this configuration.</param>
2223
/// <exception cref="ArgumentNullException">The <paramref name="providerFactory"/> is null</exception>
2324
public DataConfiguration(
@@ -26,11 +27,13 @@ public DataConfiguration(
2627
IDataCache? cache = null,
2728
IQueryGenerator? queryGenerator = null,
2829
IDataQueryLogger? queryLogger = null,
29-
IEnumerable<IDataInterceptor>? interceptors = null)
30+
IEnumerable<IDataInterceptor>? interceptors = null,
31+
int? commandTimeout = null)
3032
{
3133
ProviderFactory = providerFactory ?? throw new ArgumentNullException(nameof(providerFactory));
3234
ConnectionString = connectionString;
3335
QueryLogger = queryLogger;
36+
CommandTimeout = commandTimeout;
3437
DataCache = cache;
3538
QueryGenerator = queryGenerator ?? new SqlServerGenerator();
3639
Interceptors = interceptors ?? [];
@@ -60,6 +63,14 @@ public DataConfiguration(
6063
/// </value>
6164
public IDataQueryLogger? QueryLogger { get; }
6265

66+
/// <summary>
67+
/// Gets the default command timeout in seconds.
68+
/// </summary>
69+
/// <value>
70+
/// The default command timeout in seconds.
71+
/// </value>
72+
public int? CommandTimeout { get; }
73+
6374
/// <summary>
6475
/// Gets the data cache manager.
6576
/// </summary>
@@ -94,7 +105,7 @@ public DataConfiguration(
94105
public virtual IDataSession CreateSession(string? connectionString = null)
95106
{
96107
var connection = CreateConnection(connectionString);
97-
return new DataSession(connection, true, DataCache, QueryGenerator, QueryLogger, Interceptors);
108+
return new DataSession(connection, true, DataCache, QueryGenerator, QueryLogger, Interceptors, CommandTimeout);
98109
}
99110

100111
/// <summary>
@@ -114,7 +125,7 @@ public IDataSession CreateSession(DbTransaction transaction)
114125
if (transaction.Connection == null)
115126
throw new ArgumentException("The specified transaction doesn't have a vaild connection", nameof(transaction));
116127

117-
return new DataSession(transaction, false, DataCache, QueryGenerator, QueryLogger, Interceptors);
128+
return new DataSession(transaction, false, DataCache, QueryGenerator, QueryLogger, Interceptors, CommandTimeout);
118129
}
119130

120131
/// <summary>
@@ -157,15 +168,17 @@ public class DataConfiguration<TDiscriminator> : DataConfiguration, IDataConfigu
157168
/// <param name="cache">The data cache manager.</param>
158169
/// <param name="queryGenerator">The query generator.</param>
159170
/// <param name="queryLogger">The query command logger.</param>
171+
/// <param name="commandTimeout">The default command timeout in seconds.</param>
160172
/// <param name="interceptors">The interceptors to apply during this configuration's lifetime.</param>
161173
public DataConfiguration(
162174
DbProviderFactory providerFactory,
163175
string connectionString,
164176
IDataCache? cache = null,
165177
IQueryGenerator? queryGenerator = null,
166178
IDataQueryLogger? queryLogger = null,
167-
IEnumerable<IDataInterceptor>? interceptors = null)
168-
: base(providerFactory, connectionString, cache, queryGenerator, queryLogger, interceptors)
179+
IEnumerable<IDataInterceptor>? interceptors = null,
180+
int? commandTimeout = null)
181+
: base(providerFactory, connectionString, cache, queryGenerator, queryLogger, interceptors, commandTimeout)
169182
{
170183
}
171184
}

src/FluentCommand/DataConfigurationBuilder.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class DataConfigurationBuilder
2020
private Type? _dataCacheType;
2121
private Type? _queryGeneratorType;
2222
private Type? _queryLoggerType;
23+
private int? _commandTimeout;
2324

2425
/// <summary>
2526
/// Initializes a new instance of the <see cref="DataConfigurationBuilder"/> class.
@@ -57,6 +58,32 @@ public DataConfigurationBuilder UseConnectionString(string connectionString)
5758
return this;
5859
}
5960

61+
/// <summary>
62+
/// Sets the default command timeout in seconds.
63+
/// </summary>
64+
/// <param name="timeout">The time, in seconds, to wait for commands to execute.</param>
65+
/// <returns>
66+
/// The same configuration builder so that multiple calls can be chained.
67+
/// </returns>
68+
public DataConfigurationBuilder UseCommandTimeout(int timeout)
69+
{
70+
_commandTimeout = timeout;
71+
return this;
72+
}
73+
74+
/// <summary>
75+
/// Sets the default command timeout.
76+
/// </summary>
77+
/// <param name="timeout">The time to wait for commands to execute.</param>
78+
/// <returns>
79+
/// The same configuration builder so that multiple calls can be chained.
80+
/// </returns>
81+
public DataConfigurationBuilder UseCommandTimeout(TimeSpan timeout)
82+
{
83+
_commandTimeout = (int)timeout.TotalSeconds;
84+
return this;
85+
}
86+
6087

6188
/// <summary>
6289
/// Adds the provider factory to use with this configuration.
@@ -380,7 +407,8 @@ internal void AddConfiguration()
380407
sp.GetService(dataCache) as IDataCache,
381408
sp.GetService(queryGenerator) as IQueryGenerator,
382409
sp.GetService(queryLogger) as IDataQueryLogger,
383-
sp.GetServices<IDataInterceptor>()
410+
sp.GetServices<IDataInterceptor>(),
411+
_commandTimeout
384412
);
385413
});
386414

@@ -409,7 +437,8 @@ internal void AddConfiguration<TDiscriminator>()
409437
sp.GetService(dataCache) as IDataCache,
410438
sp.GetService(queryGenerator) as IQueryGenerator,
411439
sp.GetService(queryLogger) as IDataQueryLogger,
412-
sp.GetServices<IDataInterceptor>()
440+
sp.GetServices<IDataInterceptor>(),
441+
_commandTimeout
413442
);
414443
});
415444

src/FluentCommand/DataSession.cs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public class DataSession : DisposableBase, IDataSession
5252
/// </value>
5353
public IDataQueryLogger? QueryLogger { get; }
5454

55+
/// <summary>
56+
/// Gets the default command timeout in seconds.
57+
/// </summary>
58+
/// <value>
59+
/// The default command timeout in seconds.
60+
/// </value>
61+
public int? CommandTimeout { get; }
62+
5563
/// <summary>
5664
/// Gets the interceptors registered for this session.
5765
/// </summary>
@@ -69,6 +77,7 @@ public class DataSession : DisposableBase, IDataSession
6977
/// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
7078
/// <param name="queryGenerator">The query generator provider.</param>
7179
/// <param name="logger">The logger delegate for writing log messages.</param>
80+
/// <param name="commandTimeout">The default command timeout in seconds.</param>
7281
/// <param name="interceptors">The interceptors to apply during this session's lifetime.</param>
7382
/// <exception cref="ArgumentNullException"><paramref name="connection" /> is null</exception>
7483
/// <exception cref="ArgumentException">Invalid connection string on <paramref name="connection" /> instance.</exception>
@@ -78,7 +87,8 @@ public DataSession(
7887
IDataCache? cache = null,
7988
IQueryGenerator? queryGenerator = null,
8089
IDataQueryLogger? logger = null,
81-
IEnumerable<IDataInterceptor>? interceptors = null)
90+
IEnumerable<IDataInterceptor>? interceptors = null,
91+
int? commandTimeout = null)
8292
{
8393
if (connection == null)
8494
throw new ArgumentNullException(nameof(connection));
@@ -90,6 +100,7 @@ public DataSession(
90100
Cache = cache;
91101
QueryGenerator = queryGenerator ?? new SqlServerGenerator();
92102
QueryLogger = logger;
103+
CommandTimeout = commandTimeout;
93104

94105
_interceptors = interceptors is null ? [] : [.. interceptors];
95106
_connectionInterceptors = [.. _interceptors.OfType<IDataConnectionInterceptor>()];
@@ -106,6 +117,7 @@ public DataSession(
106117
/// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
107118
/// <param name="queryGenerator">The query generator provider.</param>
108119
/// <param name="logger">The logger delegate for writing log messages.</param>
120+
/// <param name="commandTimeout">The default command timeout in seconds.</param>
109121
/// <param name="interceptors">The interceptors to apply during this session's lifetime.</param>
110122
/// <exception cref="ArgumentNullException"><paramref name="transaction" /> is null</exception>
111123
/// <exception cref="ArgumentException">Invalid connection string on <paramref name="transaction" /> instance.</exception>
@@ -115,8 +127,9 @@ public DataSession(
115127
IDataCache? cache = null,
116128
IQueryGenerator? queryGenerator = null,
117129
IDataQueryLogger? logger = null,
118-
IEnumerable<IDataInterceptor>? interceptors = null)
119-
: this(GetTransactionConnection(transaction), disposeConnection, cache, queryGenerator, logger, interceptors)
130+
IEnumerable<IDataInterceptor>? interceptors = null,
131+
int? commandTimeout = null)
132+
: this(GetTransactionConnection(transaction), disposeConnection, cache, queryGenerator, logger, interceptors, commandTimeout)
120133
{
121134
Transaction = transaction;
122135
}
@@ -135,6 +148,7 @@ public DataSession(IDataConfiguration dataConfiguration)
135148
Cache = dataConfiguration.DataCache;
136149
QueryGenerator = dataConfiguration.QueryGenerator;
137150
QueryLogger = dataConfiguration.QueryLogger;
151+
CommandTimeout = dataConfiguration.CommandTimeout;
138152

139153
_interceptors = dataConfiguration.Interceptors is null ? [] : [.. dataConfiguration.Interceptors];
140154
_connectionInterceptors = [.. _interceptors.OfType<IDataConnectionInterceptor>()];
@@ -186,7 +200,7 @@ public async Task<DbTransaction> BeginTransactionAsync(IsolationLevel isolationL
186200
/// </returns>
187201
public IDataCommand Sql(string sql)
188202
{
189-
var dataCommand = new DataCommand(this, Transaction, _commandInterceptors);
203+
var dataCommand = new DataCommand(this, Transaction, _commandInterceptors, commandTimeout: CommandTimeout);
190204
return dataCommand.Sql(sql);
191205
}
192206

@@ -199,7 +213,7 @@ public IDataCommand Sql(string sql)
199213
/// </returns>
200214
public IDataCommand StoredProcedure(string storedProcedureName)
201215
{
202-
var dataCommand = new DataCommand(this, Transaction, _commandInterceptors);
216+
var dataCommand = new DataCommand(this, Transaction, _commandInterceptors, commandTimeout: CommandTimeout);
203217
return dataCommand.StoredProcedure(storedProcedureName);
204218
}
205219

@@ -389,6 +403,7 @@ public class DataSession<TDiscriminator> : DataSession, IDataSession<TDiscrimina
389403
/// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
390404
/// <param name="queryGenerator">The query generator provider.</param>
391405
/// <param name="logger">The logger delegate for writing log messages.</param>
406+
/// <param name="commandTimeout">The default command timeout in seconds.</param>
392407
/// <param name="interceptors">The interceptors to apply during this session's lifetime.</param>
393408
/// <exception cref="ArgumentNullException"><paramref name="connection" /> is null</exception>
394409
/// <exception cref="ArgumentException">Invalid connection string on <paramref name="connection" /> instance.</exception>
@@ -398,8 +413,9 @@ public DataSession(
398413
IDataCache? cache = null,
399414
IQueryGenerator? queryGenerator = null,
400415
IDataQueryLogger? logger = null,
401-
IEnumerable<IDataInterceptor>? interceptors = null)
402-
: base(connection, disposeConnection, cache, queryGenerator, logger, interceptors)
416+
IEnumerable<IDataInterceptor>? interceptors = null,
417+
int? commandTimeout = null)
418+
: base(connection, disposeConnection, cache, queryGenerator, logger, interceptors, commandTimeout)
403419
{
404420
}
405421

@@ -411,6 +427,7 @@ public DataSession(
411427
/// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
412428
/// <param name="queryGenerator">The query generator provider.</param>
413429
/// <param name="logger">The logger delegate for writing log messages.</param>
430+
/// <param name="commandTimeout">The default command timeout in seconds.</param>
414431
/// <param name="interceptors">The interceptors to apply during this session's lifetime.</param>
415432
/// <exception cref="ArgumentNullException"><paramref name="transaction" /> is null</exception>
416433
/// <exception cref="ArgumentException">Invalid connection string on <paramref name="transaction" /> instance.</exception>
@@ -420,8 +437,9 @@ public DataSession(
420437
IDataCache? cache = null,
421438
IQueryGenerator? queryGenerator = null,
422439
IDataQueryLogger? logger = null,
423-
IEnumerable<IDataInterceptor>? interceptors = null)
424-
: base(transaction, disposeConnection, cache, queryGenerator, logger, interceptors)
440+
IEnumerable<IDataInterceptor>? interceptors = null,
441+
int? commandTimeout = null)
442+
: base(transaction, disposeConnection, cache, queryGenerator, logger, interceptors, commandTimeout)
425443
{
426444
}
427445

src/FluentCommand/IDataConfiguration.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ public interface IDataConfiguration : IDataSessionFactory
3333
/// </value>
3434
IDataQueryLogger? QueryLogger { get; }
3535

36+
/// <summary>
37+
/// Gets the default command timeout in seconds.
38+
/// </summary>
39+
/// <value>
40+
/// The default command timeout in seconds.
41+
/// </value>
42+
int? CommandTimeout { get; }
43+
3644
/// <summary>
3745
/// Gets the data cache manager.
3846
/// </summary>

src/FluentCommand/IDataSession.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ public interface IDataSession
4545
/// </value>
4646
IDataQueryLogger? QueryLogger { get; }
4747

48+
/// <summary>
49+
/// Gets the default command timeout in seconds.
50+
/// </summary>
51+
/// <value>
52+
/// The default command timeout in seconds.
53+
/// </value>
54+
int? CommandTimeout { get; }
55+
4856
/// <summary>
4957
/// Gets the interceptors registered for this session.
5058
/// </summary>

0 commit comments

Comments
 (0)