• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / FluentCommand / 6166950777

12 Sep 2023 07:35PM UTC coverage: 51.069% (-0.04%) from 51.111%
6166950777

push

github

pwelter34
add support for registering multiple IDataSession

948 of 2392 branches covered (0.0%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 1 file covered. (100.0%)

2777 of 4902 relevant lines covered (56.65%)

161.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.59
/src/FluentCommand/DataSession.cs
1
using System.Data;
2
using System.Data.Common;
3

4
using FluentCommand.Query.Generators;
5

6
namespace FluentCommand;
7

8
/// <summary>
9
/// A fluent class for a data session.
10
/// </summary>
11
/// <seealso cref="FluentCommand.DisposableBase" />
12
/// <seealso cref="FluentCommand.IDataSession" />
13
public class DataSession : DisposableBase, IDataSession
14
{
15
    private readonly bool _disposeConnection;
16

17
    private bool _openedConnection;
18
    private int _connectionRequestCount;
19

20
    /// <summary>
21
    /// Gets the underlying <see cref="DbConnection"/> for the session.
22
    /// </summary>
23
    public DbConnection Connection { get; }
24

25
    /// <summary>
26
    /// Gets the underlying <see cref="DbTransaction"/> for the session.
27
    /// </summary>
28
    public DbTransaction Transaction { get; private set; }
29

30
    /// <summary>
31
    /// Gets the underlying <see cref="IDataCache"/> for the session.
32
    /// </summary>
33
    public IDataCache Cache { get; }
34

35
    /// <summary>
36
    /// Gets the query generator provider.
37
    /// </summary>
38
    /// <value>
39
    /// The query generator provider.
40
    /// </value>
41
    public IQueryGenerator QueryGenerator { get; }
42

43
    /// <summary>
44
    /// Gets the data command query logger.
45
    /// </summary>
46
    /// <value>
47
    /// The data command query logger.
48
    /// </value>
49
    public IDataQueryLogger QueryLogger { get; }
50

51

52
    /// <summary>
53
    /// Initializes a new instance of the <see cref="DataSession" /> class.
54
    /// </summary>
55
    /// <param name="connection">The DbConnection to use for the session.</param>
56
    /// <param name="disposeConnection">if set to <c>true</c> dispose connection with this session.</param>
57
    /// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
58
    /// <param name="queryGenerator">The query generator provider.</param>
59
    /// <param name="logger">The logger delegate for writing log messages.</param>
60
    /// <exception cref="ArgumentNullException"><paramref name="connection" /> is null</exception>
61
    /// <exception cref="ArgumentException">Invalid connection string on <paramref name="connection" /> instance.</exception>
62
    public DataSession(DbConnection connection, bool disposeConnection = true, IDataCache cache = null, IQueryGenerator queryGenerator = null, IDataQueryLogger logger = null)
1✔
63
    {
64
        if (connection == null)
1!
65
            throw new ArgumentNullException(nameof(connection));
×
66

67
        if (string.IsNullOrEmpty(connection.ConnectionString))
1!
68
            throw new ArgumentException("Invalid connection string", nameof(connection));
×
69

70
        Connection = connection;
71
        Cache = cache;
72
        QueryGenerator = queryGenerator ?? new SqlServerGenerator();
1✔
73
        QueryLogger = logger;
74

75
        _disposeConnection = disposeConnection;
1✔
76
    }
1✔
77

78
    /// <summary>
79
    /// Initializes a new instance of the <see cref="DataSession"/> class.
80
    /// </summary>
81
    /// <param name="transaction">The DbTransaction to use for the session.</param>
82
    /// <param name="disposeConnection">if set to <c>true</c> dispose connection with this session.</param>
83
    /// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
84
    /// <param name="queryGenerator">The query generator provider.</param>
85
    /// <param name="logger">The logger delegate for writing log messages.</param>
86
    /// <exception cref="ArgumentNullException"><paramref name="transaction" /> is null</exception>
87
    /// <exception cref="ArgumentException">Invalid connection string on <paramref name="transaction" /> instance.</exception>
88
    public DataSession(DbTransaction transaction, bool disposeConnection = false, IDataCache cache = null, IQueryGenerator queryGenerator = null, IDataQueryLogger logger = null)
89
        : this(transaction?.Connection, disposeConnection, cache, queryGenerator, logger)
×
90
    {
91
        Transaction = transaction ?? throw new ArgumentNullException(nameof(transaction));
×
92
    }
×
93

94
    /// <summary>
95
    /// Initializes a new instance of the <see cref="DataSession" /> class.
96
    /// </summary>
97
    /// <param name="dataConfiguration">The configuration for the session</param>
98
    /// <exception cref="ArgumentNullException"><paramref name="dataConfiguration"/> is null</exception>
99
    public DataSession(IDataConfiguration dataConfiguration)
131✔
100
    {
101
        if (dataConfiguration == null)
131!
102
            throw new ArgumentNullException(nameof(dataConfiguration));
×
103

104

105
        Connection = dataConfiguration.CreateConnection();
131✔
106
        Cache = dataConfiguration.DataCache;
131✔
107
        QueryGenerator = dataConfiguration.QueryGenerator;
131✔
108
        QueryLogger = dataConfiguration.QueryLogger;
131✔
109
        _disposeConnection = true;
131✔
110
    }
131✔
111

112

113
    /// <summary>
114
    /// Starts a database transaction with the specified isolation level.
115
    /// </summary>
116
    /// <param name="isolationLevel">Specifies the isolation level for the transaction.</param>
117
    /// <returns>
118
    /// A <see cref="DbTransaction" /> representing the new transaction.
119
    /// </returns>
120
    public DbTransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
121
    {
122
        EnsureConnection();
1✔
123
        Transaction = Connection.BeginTransaction(isolationLevel);
1✔
124

125
        return Transaction;
1✔
126
    }
127

128
#if NETCOREAPP3_0_OR_GREATER
129
    /// <summary>
130
    /// Starts a database transaction with the specified isolation level.
131
    /// </summary>
132
    /// <param name="isolationLevel">Specifies the isolation level for the transaction.</param>
133
    /// <param name="cancellationToken">The cancellation instruction.</param>
134
    /// <returns>
135
    /// A <see cref="DbTransaction" /> representing the new transaction.
136
    /// </returns>
137
    public async Task<DbTransaction> BeginTransactionAsync(IsolationLevel isolationLevel = IsolationLevel.Unspecified, CancellationToken cancellationToken = default)
138
    {
139
        await EnsureConnectionAsync(cancellationToken);
140
        Transaction = await Connection.BeginTransactionAsync(isolationLevel, cancellationToken);
141

142
        return Transaction;
143
    }
144
#endif
145

146
    /// <summary>
147
    /// Starts a data command with the specified SQL.
148
    /// </summary>
149
    /// <param name="sql">The SQL statement.</param>
150
    /// <returns>
151
    /// A fluent <see langword="interface" /> to a data command.
152
    /// </returns>
153
    public IDataCommand Sql(string sql)
154
    {
155
        var dataCommand = new DataCommand(this, Transaction);
136✔
156
        return dataCommand.Sql(sql);
136✔
157
    }
158

159
    /// <summary>
160
    /// Starts a data command with the specified stored procedure name.
161
    /// </summary>
162
    /// <param name="storedProcedureName">Name of the stored procedure.</param>
163
    /// <returns>
164
    /// A fluent <see langword="interface" /> to a data command.
165
    /// </returns>
166
    public IDataCommand StoredProcedure(string storedProcedureName)
167
    {
168
        var dataCommand = new DataCommand(this, Transaction);
5✔
169
        return dataCommand.StoredProcedure(storedProcedureName);
5✔
170
    }
171

172

173
    /// <summary>
174
    /// Ensures the connection is open.
175
    /// </summary>
176
    /// <exception cref="InvalidOperationException">Failed to open connection</exception>
177
    public void EnsureConnection()
178
    {
179
        AssertDisposed();
54✔
180

181
        if (ConnectionState.Closed == Connection.State)
54✔
182
        {
183
            Connection.Open();
52✔
184
            _openedConnection = true;
52✔
185
        }
186

187
        if (_openedConnection)
54✔
188
            _connectionRequestCount++;
54✔
189

190
        // Check the connection was opened correctly
191
        if (Connection.State is ConnectionState.Closed or ConnectionState.Broken)
54!
192
            throw new InvalidOperationException($"Execution of the command requires an open and available connection. The connection's current state is {Connection.State}.");
×
193
    }
54✔
194

195
    /// <summary>
196
    /// Ensures the connection is open asynchronous.
197
    /// </summary>
198
    /// <param name="cancellationToken">The cancellation instruction.</param>
199
    /// <returns>A task representing the asynchronous operation.</returns>
200
    /// <exception cref="InvalidOperationException">Failed to open connection</exception>
201
    public async Task EnsureConnectionAsync(CancellationToken cancellationToken = default)
202
    {
203
        AssertDisposed();
204

205
        if (ConnectionState.Closed == Connection.State)
206
        {
207
            await Connection.OpenAsync(cancellationToken).ConfigureAwait(false);
208
            _openedConnection = true;
209
        }
210

211
        if (_openedConnection)
212
            _connectionRequestCount++;
213

214
        // Check the connection was opened correctly
215
        if (Connection.State is ConnectionState.Closed or ConnectionState.Broken)
216
            throw new InvalidOperationException($"Execution of the command requires an open and available connection. The connection's current state is {Connection.State}.");
217
    }
218

219
    /// <summary>
220
    /// Releases the connection.
221
    /// </summary>
222
    public void ReleaseConnection()
223
    {
224
        AssertDisposed();
55✔
225

226
        if (!_openedConnection)
55✔
227
            return;
2✔
228

229
        if (_connectionRequestCount > 0)
53✔
230
            _connectionRequestCount--;
53✔
231

232
        if (_connectionRequestCount != 0)
53✔
233
            return;
2✔
234

235
        // When no operation is using the connection and the context had opened the connection
236
        // the connection can be closed
237
        Connection.Close();
51✔
238
        _openedConnection = false;
51✔
239
    }
51✔
240

241
#if NETCOREAPP3_0_OR_GREATER
242
    /// <summary>
243
    /// Releases the connection.
244
    /// </summary>
245
    public async Task ReleaseConnectionAsync()
246
    {
247
        AssertDisposed();
248

249
        if (!_openedConnection)
250
            return;
251

252
        if (_connectionRequestCount > 0)
253
            _connectionRequestCount--;
254

255
        if (_connectionRequestCount != 0)
256
            return;
257

258
        // When no operation is using the connection and the context had opened the connection
259
        // the connection can be closed
260
        await Connection.CloseAsync();
261
        _openedConnection = false;
262
    }
263

264
    /// <summary>
265
    /// Disposes the managed resources.
266
    /// </summary>
267
    protected override async ValueTask DisposeResourcesAsync()
268
    {
269
        if (Connection == null)
270
            return;
271

272
        // Dispose the connection created
273
        if (_disposeConnection)
274
            await Connection.DisposeAsync();
275
    }
276
#endif
277

278
    /// <summary>
279
    /// Disposes the managed resources.
280
    /// </summary>
281
    protected override void DisposeManagedResources()
282
    {
283
        if (Connection == null)
15!
284
            return;
×
285

286
        // Dispose the connection created
287
        if (_disposeConnection)
15✔
288
            Connection.Dispose();
15✔
289
    }
15✔
290
}
291

292
/// <summary>
293
/// A fluent class for a data session by discriminator.  Used to register multiple instances of IDataSession.
294
/// </summary>
295
/// <typeparam name="TDiscriminator">The type of the discriminator.</typeparam>
296
/// <seealso cref="FluentCommand.DisposableBase" />
297
/// <seealso cref="FluentCommand.IDataSession" />
298
public class DataSession<TDiscriminator> : DataSession, IDataSession<TDiscriminator>
299
{
300
    /// <summary>
301
    /// Initializes a new instance of the <see cref="DataSession" /> class.
302
    /// </summary>
303
    /// <param name="connection">The DbConnection to use for the session.</param>
304
    /// <param name="disposeConnection">if set to <c>true</c> dispose connection with this session.</param>
305
    /// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
306
    /// <param name="queryGenerator">The query generator provider.</param>
307
    /// <param name="logger">The logger delegate for writing log messages.</param>
308
    /// <exception cref="ArgumentNullException"><paramref name="connection" /> is null</exception>
309
    /// <exception cref="ArgumentException">Invalid connection string on <paramref name="connection" /> instance.</exception>
310
    public DataSession(DbConnection connection, bool disposeConnection = true, IDataCache cache = null, IQueryGenerator queryGenerator = null, IDataQueryLogger logger = null)
311
        : base(connection, disposeConnection, cache, queryGenerator, logger)
×
312
    {
313
    }
×
314

315
    /// <summary>
316
    /// Initializes a new instance of the <see cref="DataSession"/> class.
317
    /// </summary>
318
    /// <param name="transaction">The DbTransaction to use for the session.</param>
319
    /// <param name="disposeConnection">if set to <c>true</c> dispose connection with this session.</param>
320
    /// <param name="cache">The <see cref="IDataCache" /> used to cached results of queries.</param>
321
    /// <param name="queryGenerator">The query generator provider.</param>
322
    /// <param name="logger">The logger delegate for writing log messages.</param>
323
    /// <exception cref="ArgumentNullException"><paramref name="transaction" /> is null</exception>
324
    /// <exception cref="ArgumentException">Invalid connection string on <paramref name="transaction" /> instance.</exception>
325
    public DataSession(DbTransaction transaction, bool disposeConnection = false, IDataCache cache = null, IQueryGenerator queryGenerator = null, IDataQueryLogger logger = null)
326
        : base(transaction, disposeConnection, cache, queryGenerator, logger)
×
327
    {
328
    }
×
329

330
    /// <summary>
331
    /// Initializes a new instance of the <see cref="DataSession" /> class.
332
    /// </summary>
333
    /// <param name="dataConfiguration">The configuration for the session</param>
334
    /// <exception cref="ArgumentNullException"><paramref name="dataConfiguration" /> is null</exception>
335
    public DataSession(IDataConfiguration<TDiscriminator> dataConfiguration)
336
        : base(dataConfiguration)
×
337
    {
338
    }
×
339
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc