<commit_before>﻿using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;

namespace Enexure.Fire.Data
{
	public class UnitOfWork : IUnitOfWork
	{
		private readonly IsolationLevel isolationLevel;
		private DbTransaction transaction;
		private readonly DbConnection connection;

		public DbConnection Connection
		{
			get { return connection; }
		}

		public DbTransaction Transaction
		{
			get { return GetOrCreateTransaction(); }
		}

		public UnitOfWork(DbConnection connection, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
			: this(connection, null, isolationLevel)
		{

		}

		public UnitOfWork(DbConnection connection, DbTransaction transaction, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
		{
			if (connection == null) throw new ArgumentNullException("connection", "You must specify a connection");

			this.connection = connection;
			this.isolationLevel = isolationLevel;
			this.transaction = transaction;
		}

		internal DbTransaction GetOrCreateTransaction()
		{
			if (Connection.State == ConnectionState.Closed) {
				Connection.Open();
			}

			return GetTransaction();
		}

		internal Task<DbTransaction> GetOrCreateTransactionAsync()
		{
			return GetOrCreateTransactionAsync(CancellationToken.None);
		}

		internal async Task<DbTransaction> GetOrCreateTransactionAsync(CancellationToken cancellationToken)
		{
			var spinner = WaitForConnection(cancellationToken);
			var timeout = Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
			if (await Task.WhenAny(spinner, timeout) == timeout)
			{
				throw new TimeoutException("Timeout expired while waiting for the connection to open");
			}

			if (Connection.State == ConnectionState.Closed) {
				await Connection.OpenAsync(cancellationToken);
			}
			return GetTransaction();
		}

		private async Task WaitForConnection(CancellationToken cancellationToken)
		{
			while (!cancellationToken.IsCancellationRequested 
				&& Connection.State == ConnectionState.Connecting)
			{
				await Task.Delay(1, cancellationToken);
			}
		}

		private DbTransaction GetTransaction()
		{
			return transaction ?? (transaction = Connection.BeginTransaction(isolationLevel));
		}

		private void EndCurrentTransaction()
		{
			if (transaction != null) {
				transaction.Dispose();
			}

			transaction = null;
		}

		internal DbCommand CreateCommand()
		{
			var command = Connection.CreateCommand();
			return command;
		}

		public bool IsConnectionOpen
		{
			get
			{
				return Connection.State != ConnectionState.Closed &&
					   Connection.State != ConnectionState.Broken;
			}
		}

		public void Dispose()
		{
			EndCurrentTransaction();
			Connection.Close();
			Connection.Dispose();
		}

		public void Commit()
		{
			if (transaction != null) {

				transaction.Commit();
				EndCurrentTransaction();
			}
		}

		public void Rollback()
		{
			if (transaction != null) {

				transaction.Rollback();
				EndCurrentTransaction();
			}
		}

	}
}<commit_msg>Don't end the transaction in UnitOfWork until the unit of work is disposed<commit_after>﻿using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;

namespace Enexure.Fire.Data
{
	public class UnitOfWork : IUnitOfWork
	{
		private readonly IsolationLevel isolationLevel;
		private DbTransaction transaction;
		private readonly DbConnection connection;

		public DbConnection Connection
		{
			get { return connection; }
		}

		public DbTransaction Transaction
		{
			get { return GetOrCreateTransaction(); }
		}

		public UnitOfWork(DbConnection connection, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
			: this(connection, null, isolationLevel)
		{

		}

		public UnitOfWork(DbConnection connection, DbTransaction transaction, IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
		{
			if (connection == null) throw new ArgumentNullException("connection", "You must specify a connection");

			this.connection = connection;
			this.isolationLevel = isolationLevel;
			this.transaction = transaction;
		}

		internal DbTransaction GetOrCreateTransaction()
		{
			if (Connection.State == ConnectionState.Closed) {
				Connection.Open();
			}

			return GetTransaction();
		}

		internal Task<DbTransaction> GetOrCreateTransactionAsync()
		{
			return GetOrCreateTransactionAsync(CancellationToken.None);
		}

		internal async Task<DbTransaction> GetOrCreateTransactionAsync(CancellationToken cancellationToken)
		{
			var spinner = WaitForConnection(cancellationToken);
			var timeout = Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
			if (await Task.WhenAny(spinner, timeout) == timeout)
			{
				throw new TimeoutException("Timeout expired while waiting for the connection to open");
			}

			if (Connection.State == ConnectionState.Closed) {
				await Connection.OpenAsync(cancellationToken);
			}
			return GetTransaction();
		}

		private async Task WaitForConnection(CancellationToken cancellationToken)
		{
			while (!cancellationToken.IsCancellationRequested 
				&& Connection.State == ConnectionState.Connecting)
			{
				await Task.Delay(1, cancellationToken);
			}
		}

		private DbTransaction GetTransaction()
		{
			return transaction ?? (transaction = Connection.BeginTransaction(isolationLevel));
		}

		private void EndCurrentTransaction()
		{
			if (transaction != null) {
				transaction.Dispose();
			}

			transaction = null;
		}

		internal DbCommand CreateCommand()
		{
			var command = Connection.CreateCommand();
			return command;
		}

		public bool IsConnectionOpen
		{
			get
			{
				return Connection.State != ConnectionState.Closed &&
					   Connection.State != ConnectionState.Broken;
			}
		}

		public void Dispose()
		{
			EndCurrentTransaction();
			Connection.Close();
			Connection.Dispose();
		}

		public void Commit()
		{
			if (transaction != null) {
				transaction.Commit();
			}
		}

		public void Rollback()
		{
			if (transaction != null) {
				transaction.Rollback();
			}
		}

	}
}
{'fraction_non_alphanumeric': 0.09184180043024988, 'fraction_numerical': 0.0006619228859837829, 'mean_word_length': 4.074727120067171, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4023169', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1634, 'n_words': 388}