├── .gitattributes ├── .gitignore ├── BREAKING_CHANGES.md ├── GitReleaseManager.yaml ├── GitVersionConfig.yaml ├── LICENSE ├── NHibernate.SqlAzure.Tests ├── App.Release.config ├── App.config ├── Config │ ├── FluentRunner.cs │ ├── LocalTestingReliableSql2008ClientDriver.cs │ ├── NHibernateConfiguration.cs │ ├── NHibernateTestBase.cs │ └── SqlExpressTransientErrorDetectionStrategy.cs ├── ConnectionTests.cs ├── Entities │ ├── User.cs │ └── UserProperty.cs ├── Migrations │ ├── 20120801141148_CreateUserTable.cs │ └── 20120809201500_CreateUserPropertyTable.cs ├── NHibernate.SqlAzure.Tests.csproj ├── Properties │ └── AssemblyInfo.cs ├── SqlClientDriverTests.cs ├── TransientErrorDetectionTests.cs └── packages.config ├── NHibernate.SqlAzure.sln ├── NHibernate.SqlAzure ├── DefaultReliableSql2008ClientDriver.cs ├── NHibernate.SqlAzure.Standalone.nuspec ├── NHibernate.SqlAzure.csproj ├── NHibernate.SqlAzure.nuspec ├── Properties │ └── AssemblyInfo.cs ├── ReliableAdoNetTransactionFactory.cs ├── ReliableAdoNetWithDistributedTransactionFactory.cs ├── ReliableAdoTransaction.cs ├── ReliableSql2008ClientDriver.cs ├── ReliableSqlClientBatchingBatcher.cs ├── ReliableSqlClientBatchingBatcherFactory.cs ├── ReliableSqlCommand.cs ├── ReliableSqlDbConnection.cs ├── RetryStrategies │ ├── SqlAzureTransientErrorDetectionStrategy.cs │ └── SqlAzureTransientErrorDetectionStrategyWithTimeouts.cs ├── SqlAzureClientDriver.cs ├── SqlAzureClientDriverWithTimeoutRetries.cs └── packages.config ├── NHibernate4.SqlAzure.Tests ├── App.Release.config ├── App.config ├── NHibernate4.SqlAzure.Tests.csproj ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── NHibernate4.SqlAzure ├── NHibernate4.SqlAzure.Standalone.nuspec ├── NHibernate4.SqlAzure.csproj ├── NHibernate4.SqlAzure.nuspec ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── NHibernate5.SqlAzure.Tests ├── App.Release.config ├── App.config ├── App_Start │ ├── NHibernateProfilerBootstrapper.cs │ └── NHibernateProfilerBootstrapper.vb ├── NHibernate5.SqlAzure.Tests.csproj ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── NHibernate5.SqlAzure ├── NHibernate5.SqlAzure.Standalone.nuspec ├── NHibernate5.SqlAzure.csproj ├── NHibernate5.SqlAzure.nuspec ├── Properties │ └── AssemblyInfo.cs ├── ReliableAdoNetWithDistributedTransactionFactory.cs ├── ReliableSql2008ClientDriver.cs ├── ReliableSqlClientBatchingBatcher.cs ├── ReliableSqlCommand.cs └── packages.config ├── PreBuild.ps1 ├── README.md ├── logo.png └── packages └── repositories.config /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | # Custom for Visual Studio 4 | *.cs diff=csharp 5 | *.sln merge=union 6 | *.csproj merge=union 7 | *.vbproj merge=union 8 | *.fsproj merge=union 9 | *.dbproj merge=union 10 | 11 | # Normalise endings to CRLF 12 | *.cs eol=crlf 13 | *.xml eol=crlf 14 | *.xaml eol=crlf 15 | *.xsl eol=crlf 16 | *.xsd eol=crlf 17 | *.cshtml eol=crlf 18 | *.css eol=crlf 19 | *.js eol=crlf 20 | *.txt eol=crlf 21 | *.config eol=crlf 22 | *.sql eol=crlf 23 | *.sln eol=crlf 24 | *.csproj eol=crlf 25 | *.vbproj eol=crlf 26 | *.fsproj eol=crlf 27 | *.dbproj eol=crlf 28 | *.nunit eol=crlf 29 | *.html eol=crlf 30 | *.md eol=crlf 31 | *.proj eol=crlf 32 | *.bat eol=crlf 33 | *.cmd eol=crlf 34 | *.nuspec eol=crlf 35 | *.targets eol=crlf 36 | *.conf eol=crlf 37 | *.manifest eol=crlf 38 | *.ps1 eol=crlf 39 | *.resx eol=crlf 40 | *.asax eol=crlf 41 | *.aspx eol=crlf 42 | *.ncrunchproject eol=crlf 43 | *.ncrunchsolution eol=crlf 44 | *.msbuild eol=crlf 45 | *.template eol=crlf 46 | *.settings eol=crlf 47 | *.java eol=crlf 48 | .gitattributes eol=crlf 49 | .classpath eol=crlf 50 | .project eol=crlf 51 | 52 | # Standard to msysgit 53 | *.doc diff=astextplain 54 | *.DOC diff=astextplain 55 | *.docx diff=astextplain 56 | *.DOCX diff=astextplain 57 | *.dot diff=astextplain 58 | *.DOT diff=astextplain 59 | *.pdf diff=astextplain 60 | *.PDF diff=astextplain 61 | *.rtf diff=astextplain 62 | *.RTF diff=astextplain 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | _ReSharper* 4 | *.csproj.user 5 | *.ReSharper.user 6 | *.ReSharper 7 | *.user 8 | *.suo 9 | *.cache 10 | ~$* 11 | *~ 12 | *.log 13 | packages 14 | *.ncrunch* 15 | *.DotSettings 16 | /.vs/NHibernate.SqlAzure/v15/Server/sqlite3 17 | -------------------------------------------------------------------------------- /BREAKING_CHANGES.md: -------------------------------------------------------------------------------- 1 | AzureWebFarm.OctopusDeploy Breaking Changes 2 | ------------------------------------------- 3 | 4 | Version 2.0 5 | =========== 6 | 7 | Version 2 of this library targets the new version (6) of the Enterprise Library code and as such requires .NET 4.5. If you have a .NET 4.0 application then feel free to use the [latest version in the 1.0 range of this library](https://www.nuget.org/packages/NHibernate.SqlAzure/1.0.0.37). 8 | 9 | Version 2 also removes strong naming of the assembly - if you need strong naming then use version 1. 10 | -------------------------------------------------------------------------------- /GitReleaseManager.yaml: -------------------------------------------------------------------------------- 1 | create: 2 | include-footer: true 3 | footer-heading: Where to get it 4 | footer-content: You can download this release from [nuget](https://www.nuget.org/packages?q=nhibernate.sqlazure) 5 | footer-includes-milestone: false 6 | milestone-replace-text: '{milestone}' 7 | export: 8 | include-created-date-in-title: false 9 | created-date-string-format: MMMM dd, yyyy 10 | perform-regex-removal: false 11 | regex-text: '### Where to get it(\r\n)*You can .*\)' 12 | multiline-regex: false 13 | issue-labels-include: 14 | - Bug 15 | - Feature 16 | - Improvement 17 | issue-labels-exclude: 18 | - Internal Refactoring 19 | -------------------------------------------------------------------------------- /GitVersionConfig.yaml: -------------------------------------------------------------------------------- 1 | next-version: 3.0.0 2 | branches: {} 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 by Robert Moore 2 | 3 | The source code for NHibernate.SqlAzure is available under an MIT license as 4 | per below. If you are using the version of NHibernate.SqlAzure that is combined 5 | with the EnterpriseLibrary dlls then it is available under the EnterpriseLibrary 6 | license as per http://entlib.codeplex.com/license. 7 | 8 | ----- 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/App.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Config/FluentRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Reflection; 4 | using FluentMigrator.Runner.Announcers; 5 | using FluentMigrator.Runner.Initialization; 6 | 7 | namespace NHibernate.SqlAzure.Tests.Config 8 | { 9 | public class FluentRunner 10 | { 11 | private readonly string _connectionString; 12 | private readonly Assembly _migrationAssembly; 13 | private readonly string _database; 14 | private long _version; 15 | private string _task; 16 | 17 | public FluentRunner(string connectionString, Assembly migrationAssembly, string database = "sqlserver2008") 18 | { 19 | _connectionString = connectionString; 20 | _migrationAssembly = migrationAssembly; 21 | _database = database; 22 | } 23 | 24 | public void MigrateTo(long version) 25 | { 26 | _version = version; 27 | _task = _version == 0 ? "rollback:all" : "rollback:toversion"; 28 | Execute(); 29 | } 30 | 31 | public void MigrateToLatest() 32 | { 33 | _task = "migrate:up"; 34 | Execute(); 35 | } 36 | 37 | private void Execute() 38 | { 39 | var announcer = new TextWriterAnnouncer(Console.Out) {ShowElapsedTime = true, ShowSql = true}; 40 | var runnerContext = new RunnerContext(announcer) 41 | { 42 | Database = _database, 43 | Task = _task, 44 | Connection = _connectionString, 45 | Target = _migrationAssembly.CodeBase.Replace("file:///", ""), 46 | Version = _version 47 | }; 48 | 49 | Trace.TraceInformation("#\n# Executing migration task {0}...\n#\n", _task); 50 | var task = new TaskExecutor(runnerContext); 51 | task.Execute(); 52 | Trace.TraceInformation("\n#\n# Task {0} complete!\n#", _task); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Config/LocalTestingReliableSql2008ClientDriver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 3 | 4 | namespace NHibernate.SqlAzure.Tests.Config 5 | { 6 | public class LocalTestingReliableSql2008ClientDriver : DefaultReliableSql2008ClientDriver 7 | { 8 | protected override EventHandler CommandRetryEventHandler() 9 | { 10 | return LogRetry("Command"); 11 | } 12 | 13 | protected override EventHandler ConnectionRetryEventHandler() 14 | { 15 | return LogRetry("Connection"); 16 | } 17 | 18 | private static EventHandler LogRetry(string type) 19 | { 20 | return (sender, args) => 21 | { 22 | var msg = String.Format("SQLAzureClientDriver {3} Retry - Count:{0}, Delay:{1}, Exception:{2}\r\n\r\n", args.CurrentRetryCount, args.Delay, args.LastException, type); 23 | Console.WriteLine(msg); 24 | }; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Config/NHibernateConfiguration.cs: -------------------------------------------------------------------------------- 1 | using FluentNHibernate.Automapping; 2 | using FluentNHibernate.Automapping.Alterations; 3 | using FluentNHibernate.Cfg; 4 | using FluentNHibernate.Cfg.Db; 5 | using HibernatingRhinos.Profiler.Appender.NHibernate; 6 | using NHibernate.Cfg; 7 | using NHibernate.Driver; 8 | using NHibernate.SqlAzure.Tests.Entities; 9 | using NHibernate.Tool.hbm2ddl; 10 | 11 | namespace NHibernate.SqlAzure.Tests.Config 12 | { 13 | public class NHibernateConfiguration where T : SqlClientDriver 14 | { 15 | private readonly string _connectionString; 16 | private readonly IPersistenceConfigurer _databaseConfig; 17 | 18 | public NHibernateConfiguration(string connectionString, IPersistenceConfigurer databaseConfig = null) 19 | { 20 | _connectionString = connectionString; 21 | _databaseConfig = databaseConfig ?? MsSqlConfiguration.MsSql2008.ConnectionString(_connectionString).Driver(); 22 | } 23 | 24 | public ISessionFactory GetSessionFactory() 25 | { 26 | NHibernateProfiler.Initialize(); 27 | 28 | var config = Fluently.Configure() 29 | .Database(_databaseConfig) 30 | .Mappings(m => m.AutoMappings 31 | .Add(AutoMap.AssemblyOf>() 32 | .Where(type => type.Namespace != null && type.Namespace.EndsWith("Entities")) 33 | .UseOverridesFromAssemblyOf>() 34 | ) 35 | ) 36 | // Ensure batching is used 37 | .ExposeConfiguration(c => c.SetProperty(Environment.BatchSize, "10")) 38 | // Turn off cache to make sure all calls actually go to the database 39 | .ExposeConfiguration(c => c.SetProperty(Environment.UseQueryCache, "false")) 40 | .ExposeConfiguration(c => c.SetProperty(Environment.UseSecondLevelCache, "false")); 41 | 42 | if (typeof(LocalTestingReliableSql2008ClientDriver).IsAssignableFrom(typeof(T))) 43 | config.ExposeConfiguration(c => c.SetProperty(Environment.TransactionStrategy, 44 | typeof(ReliableAdoNetWithDistributedTransactionFactory).AssemblyQualifiedName)); 45 | 46 | var nhConfig = config.BuildConfiguration(); 47 | SchemaMetadataUpdater.QuoteTableAndColumns(nhConfig); 48 | var validator = new SchemaValidator(nhConfig); 49 | validator.Validate(); 50 | 51 | return config.BuildSessionFactory(); 52 | } 53 | } 54 | 55 | public class UserPropertyOverride : IAutoMappingOverride 56 | { 57 | public void Override(AutoMapping mapping) 58 | { 59 | mapping.CompositeId().KeyProperty(u => u.Name).KeyReference(u => u.User, "UserId"); 60 | } 61 | } 62 | 63 | public class UserOverride : IAutoMappingOverride 64 | { 65 | public void Override(AutoMapping mapping) 66 | { 67 | mapping.HasMany(u => u.Properties).KeyColumn("UserId").Cascade.All(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Config/NHibernateTestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using System.Data.SqlClient; 4 | using System.ServiceProcess; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using NHibernate.Driver; 8 | using NUnit.Framework; 9 | 10 | namespace NHibernate.SqlAzure.Tests.Config 11 | { 12 | public abstract class PooledNHibernateTestBase : NHibernateTestBase 13 | where T:SqlClientDriver 14 | { 15 | protected override string ConnectionString 16 | { 17 | get { return ConfigurationManager.ConnectionStrings["PooledDatabase"].ConnectionString; } 18 | } 19 | } 20 | 21 | public abstract class NonPooledNHibernateTestBase : NHibernateTestBase 22 | where T : SqlClientDriver 23 | { 24 | protected override string ConnectionString 25 | { 26 | get { return ConfigurationManager.ConnectionStrings["NonPooledDatabase"].ConnectionString; } 27 | } 28 | } 29 | 30 | public abstract class NHibernateTestBase where T: SqlClientDriver 31 | { 32 | private ISessionFactory _sessionFactory; 33 | protected FluentRunner Migrator; 34 | 35 | protected abstract string ConnectionString { get; } 36 | 37 | [TestFixtureSetUp] 38 | public void TestFixtureSetup() 39 | { 40 | CreateTestDatabase(); 41 | 42 | Migrator = new FluentRunner(ConnectionString, typeof(NHibernateConfiguration<>).Assembly); 43 | 44 | if (_sessionFactory != null) 45 | return; 46 | 47 | Migrator.MigrateToLatest(); 48 | 49 | var nHibernateConfig = new NHibernateConfiguration(ConnectionString); 50 | _sessionFactory = nHibernateConfig.GetSessionFactory(); 51 | } 52 | 53 | private void CreateTestDatabase() 54 | { 55 | var connectionBuilder = new SqlConnectionStringBuilder(ConnectionString); 56 | var testDatabaseName = connectionBuilder.InitialCatalog; 57 | connectionBuilder.InitialCatalog = "master"; 58 | using (var connection = new SqlConnection(connectionBuilder.ToString())) 59 | { 60 | connection.Open(); 61 | using (var command = new System.Data.SqlClient.SqlCommand( 62 | string.Format("USE master IF NOT EXISTS(select * from sys.databases where name = '{0}') CREATE DATABASE {0}", testDatabaseName), connection 63 | )) 64 | { 65 | command.ExecuteNonQuery(); 66 | } 67 | } 68 | } 69 | 70 | protected ISession CreateSession() 71 | { 72 | return _sessionFactory.OpenSession(); 73 | } 74 | 75 | #region SQLExpress shutdown code 76 | private readonly ServiceController _serviceController = new ServiceController { MachineName = Environment.MachineName, ServiceName = ConfigurationManager.AppSettings["SqlServerServiceName"] }; 77 | 78 | [TearDown] 79 | public void TearDown() 80 | { 81 | // Make sure that the service is running before stopping the test 82 | _serviceController.Refresh(); 83 | if (_serviceController.Status == ServiceControllerStatus.PausePending) 84 | _serviceController.WaitForStatus(ServiceControllerStatus.Paused); 85 | if (_serviceController.Status == ServiceControllerStatus.ContinuePending) 86 | _serviceController.WaitForStatus(ServiceControllerStatus.Running); 87 | 88 | if (_serviceController.Status != ServiceControllerStatus.Running) 89 | { 90 | Console.WriteLine("SQLExpress service currently at {0} state; restarting...", _serviceController.Status); 91 | _serviceController.Continue(); 92 | _serviceController.WaitForStatus(ServiceControllerStatus.Running); 93 | } 94 | } 95 | 96 | protected CancellableTask TemporarilyShutdownSqlServerExpress() 97 | { 98 | var tokenSource = new CancellationTokenSource(); 99 | Task.Run(() => 100 | { 101 | // tests run for about 5 seconds, 102 | // lets wait for 1 second and then pause for 3 seconds, this will assure a retry and a retry with backoff will happen 103 | 104 | Thread.Sleep(1000); 105 | 106 | _serviceController.Refresh(); 107 | if (_serviceController.Status == ServiceControllerStatus.Running) 108 | _serviceController.Pause(); 109 | _serviceController.WaitForStatus(ServiceControllerStatus.Paused); 110 | 111 | Console.WriteLine(DateTime.Now.ToString("s:fff") + " SQLServer paused"); 112 | Thread.Sleep(3000); 113 | 114 | _serviceController.Refresh(); 115 | _serviceController.Continue(); 116 | _serviceController.WaitForStatus(ServiceControllerStatus.Running); 117 | Console.WriteLine(DateTime.Now.ToString("s:fff") + " SQLServer continued"); 118 | 119 | }, tokenSource.Token); 120 | 121 | return new CancellableTask(tokenSource); 122 | } 123 | 124 | protected class CancellableTask : IDisposable 125 | { 126 | private readonly CancellationTokenSource _tokenSource; 127 | 128 | public CancellableTask(CancellationTokenSource tokenSource) 129 | { 130 | _tokenSource = tokenSource; 131 | } 132 | 133 | public void Dispose() 134 | { 135 | _tokenSource.Cancel(); 136 | } 137 | } 138 | #endregion 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Config/SqlExpressTransientErrorDetectionStrategy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Linq; 4 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 5 | 6 | namespace NHibernate.SqlAzure.Tests.Config 7 | { 8 | public class SqlExpressTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy 9 | { 10 | public bool IsTransient(Exception ex) 11 | { 12 | if (ex is TransactionException) 13 | ex = ex.InnerException; 14 | 15 | // Is the error an error 17142 - The service is paused 16 | // Is the error an error 233 - Connection error when the process isn't responding 17 | var sqlException = ex as SqlException; 18 | return sqlException != null 19 | && sqlException.Errors.Cast().Any(error => error.Number == 17142 || error.Number == 233); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/ConnectionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | using System.Threading; 4 | using NHibernate.Driver; 5 | using NHibernate.SqlAzure.Tests.Config; 6 | using NUnit.Framework; 7 | 8 | namespace NHibernate.SqlAzure.Tests 9 | { 10 | [TestFixture] 11 | class WhenConnectingLocalTestingSqlAzureClientDriverShould : ConnectionTests 12 | { 13 | [Test] 14 | public void Establish_connection_during_temporary_shutdown_of_sql_server() 15 | { 16 | TestConnectionEstablishment(); 17 | } 18 | } 19 | 20 | [TestFixture] 21 | class WhenConnectingSql2008ClientDriverShould : ConnectionTests 22 | { 23 | [Test] 24 | public void Fail_to_establish_connection_during_temporary_shutdown_of_sql_server() 25 | { 26 | Assert.Throws(TestConnectionEstablishment, "No SqlException was thrown during temporary shutdown of SQL server, but one was expected."); 27 | } 28 | } 29 | 30 | abstract class ConnectionTests : NonPooledNHibernateTestBase 31 | where T : SqlClientDriver 32 | { 33 | protected void TestConnectionEstablishment() 34 | { 35 | using (TemporarilyShutdownSqlServerExpress()) 36 | { 37 | for (var i = 0; i < 100; i++) 38 | { 39 | using (var session = CreateSession()) 40 | { 41 | Assert.That(session.Connection.State == ConnectionState.Open); 42 | Thread.Sleep(50); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Entities/User.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NHibernate.SqlAzure.Tests.Entities 4 | { 5 | public class User 6 | { 7 | public virtual int Id { get; set; } 8 | public virtual string Name { get; set; } 9 | public virtual IList Properties { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Entities/UserProperty.cs: -------------------------------------------------------------------------------- 1 | namespace NHibernate.SqlAzure.Tests.Entities 2 | { 3 | public class UserProperty 4 | { 5 | public virtual User User { get; set; } 6 | public virtual string Name { get; set; } 7 | public virtual string Value { get; set; } 8 | 9 | #region Equals 10 | public override bool Equals(object obj) 11 | { 12 | if (obj == null) 13 | return false; 14 | var a = obj as UserProperty; 15 | if (a == null) 16 | return false; 17 | if (User.Id == a.User.Id && Name == a.Name) 18 | return true; 19 | return false; 20 | } 21 | public override int GetHashCode() 22 | { 23 | return string.Format("{0}|{1}", User.Id, Name).GetHashCode(); 24 | } 25 | #endregion 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Migrations/20120801141148_CreateUserTable.cs: -------------------------------------------------------------------------------- 1 | using FluentMigrator; 2 | 3 | namespace NHibernate.SqlAzure.Tests.Migrations 4 | { 5 | [Migration(20120801141148)] 6 | public class CreateUserTable : Migration 7 | { 8 | public override void Up() 9 | { 10 | Create.Table("User") 11 | .WithColumn("Id").AsInt32().PrimaryKey().Identity() 12 | .WithColumn("Name").AsString(255).NotNullable(); 13 | } 14 | 15 | public override void Down() 16 | { 17 | Delete.Table("User"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Migrations/20120809201500_CreateUserPropertyTable.cs: -------------------------------------------------------------------------------- 1 | using FluentMigrator; 2 | 3 | namespace NHibernate.SqlAzure.Tests.Migrations 4 | { 5 | [Migration(20120809201500)] 6 | public class CreateUserPropertyTable : Migration 7 | { 8 | public override void Up() 9 | { 10 | Create.Table("UserProperty") 11 | .WithColumn("UserId").AsInt32().PrimaryKey() 12 | .WithColumn("Name").AsString(255).PrimaryKey() 13 | .WithColumn("Value").AsString(255); 14 | } 15 | 16 | public override void Down() 17 | { 18 | Delete.Table("User"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/NHibernate.SqlAzure.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {887FD0A4-B8E0-4B3D-BF7E-4CC7090EB829} 9 | Library 10 | Properties 11 | NHibernate.SqlAzure.Tests 12 | NHibernate.SqlAzure.Tests 13 | v4.5 14 | 512 15 | ..\ 16 | 17 | 18 | 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | false 38 | 39 | 40 | 41 | False 42 | ..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll 43 | 44 | 45 | False 46 | ..\packages\FluentMigrator.1.1.2.1\lib\40\FluentMigrator.dll 47 | 48 | 49 | False 50 | ..\packages\FluentMigrator.Runner.1.1.1.26\lib\NET40\FluentMigrator.Runner.dll 51 | 52 | 53 | False 54 | ..\packages\FluentNHibernate.1.4.0.0\lib\net35\FluentNHibernate.dll 55 | 56 | 57 | False 58 | ..\packages\NHibernateProfiler.1.0.0.951\lib\Net40\HibernatingRhinos.Profiler.Appender.v4.0.dll 59 | 60 | 61 | False 62 | ..\packages\Iesi.Collections.3.2.0.4000\lib\Net35\Iesi.Collections.dll 63 | 64 | 65 | ..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll 66 | 67 | 68 | ..\packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll 69 | 70 | 71 | True 72 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 73 | 74 | 75 | False 76 | ..\packages\NHibernate.3.3.3.4001\lib\Net35\NHibernate.dll 77 | 78 | 79 | ..\packages\NUnit.2.6.4\lib\nunit.framework.dll 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | False 93 | ..\packages\WebActivator.1.4.4\lib\net40\WebActivator.dll 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Designer 114 | true 115 | 116 | 117 | App.config 118 | True 119 | 120 | 121 | 122 | 123 | 124 | {C51908DF-FAEA-4EAA-8F75-096346537C33} 125 | NHibernate.SqlAzure 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 136 | 137 | 138 | 139 | 146 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NHibernate.SqlAzure.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NHibernate.SqlAzure.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("372cfa0d-2ae7-485c-952a-c0bd7d6cf86f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/SqlClientDriverTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using FizzWare.NBuilder; 6 | using NHibernate.Driver; 7 | using NHibernate.Exceptions; 8 | using NHibernate.SqlAzure.Tests.Config; 9 | using NHibernate.SqlAzure.Tests.Entities; 10 | using NUnit.Framework; 11 | 12 | namespace NHibernate.SqlAzure.Tests 13 | { 14 | // Run the tests against the standard Sql2008Client driver as well as the SqlAzureClientDriver 15 | // That way, we know if the test is broken because of the SqlAzureClientDriver or the test is wrong 16 | // Also, test the retry logic actually fires by using the LocalTestingReliableSql2008ClientDriver that provides 17 | // a reliable connection with a local error specific transient error detection strategy 18 | [TestFixture] 19 | class LocalTestingSqlAzureClientDriverShould : SqlClientDriverShould 20 | { 21 | [Test] 22 | public void Execute_non_batching_commands_during_temporary_shutdown_of_sql_server() 23 | { 24 | using (TemporarilyShutdownSqlServerExpress()) 25 | { 26 | for (var i = 0; i < 100; i++) 27 | { 28 | Insert_and_select_entity(); 29 | Thread.Sleep(50); 30 | } 31 | } 32 | } 33 | 34 | [Test] 35 | public void Execute_batching_commands_during_temporary_shutdown_of_sql_server() 36 | { 37 | using (TemporarilyShutdownSqlServerExpress()) 38 | { 39 | for (var i = 0; i < 100; i++) 40 | { 41 | Insert_and_select_multiple_entities(); 42 | Thread.Sleep(50); 43 | } 44 | } 45 | } 46 | } 47 | 48 | [TestFixture] 49 | class SqlAzureClientDriverShould : SqlClientDriverShould { } 50 | 51 | [TestFixture] 52 | class SqlAzureClientDriverWithTimeoutRetriesShould : SqlClientDriverShould { } 53 | 54 | [TestFixture] 55 | class Sql2008ClientDriverShould : SqlClientDriverShould 56 | { 57 | [Test] 58 | [ExpectedException(typeof(ExpectedErrorException))] 59 | public void Fail_to_execute_non_batching_commands_during_temporary_shutdown_of_sql_server() 60 | { 61 | try 62 | { 63 | using (TemporarilyShutdownSqlServerExpress()) 64 | { 65 | for (var i = 0; i < 100; i++) 66 | { 67 | Insert_and_select_entity(); 68 | Thread.Sleep(50); 69 | } 70 | } 71 | } 72 | catch (GenericADOException e) 73 | { 74 | Console.WriteLine(e); 75 | throw new ExpectedErrorException(); 76 | } 77 | Assert.Fail("There was no exception when executing non batching commands during temporary shutdown of SQL server, but one was expected."); 78 | } 79 | 80 | [Test] 81 | [ExpectedException(typeof(ExpectedErrorException))] 82 | public void Fail_to_execute_batching_commands_during_temporary_shutdown_of_sql_server() 83 | { 84 | try 85 | { 86 | using (TemporarilyShutdownSqlServerExpress()) 87 | { 88 | for (var i = 0; i < 100; i++) 89 | { 90 | Insert_and_select_multiple_entities(); 91 | Thread.Sleep(50); 92 | } 93 | } 94 | } 95 | catch (GenericADOException e) 96 | { 97 | Console.WriteLine(e); 98 | throw new ExpectedErrorException(); 99 | } 100 | catch (TransactionException e) 101 | { 102 | Console.WriteLine(e); 103 | throw new ExpectedErrorException(); 104 | } 105 | } 106 | public class ExpectedErrorException : Exception { } 107 | } 108 | 109 | abstract class SqlClientDriverShould : PooledNHibernateTestBase where T : SqlClientDriver 110 | { 111 | [Test] 112 | public void Perform_empty_select() 113 | { 114 | using (var session = CreateSession()) 115 | { 116 | var user = session.Get(-1); 117 | 118 | Assert.That(user, Is.Null); 119 | } 120 | } 121 | 122 | [Test] 123 | public void Insert_and_select_entity() 124 | { 125 | using (var session = CreateSession()) 126 | using (var session2 = CreateSession()) 127 | { 128 | var user = new User { Name = "Name" }; 129 | session.Save(user); 130 | 131 | var dbUser = session2.Get(user.Id); 132 | 133 | Assert.That(dbUser.Name, Is.EqualTo(user.Name)); 134 | } 135 | } 136 | 137 | [Test] 138 | public void Insert_and_select_multiple_entities() 139 | { 140 | using (var session = CreateSession()) 141 | using (var session2 = CreateSession()) 142 | { 143 | var users = Builder.CreateListOfSize(100) 144 | .All().With(u => u.Properties = new List 145 | { 146 | new UserProperty {Name = "Name", Value = "Value", User = u} 147 | }) 148 | .Build().OrderBy(u => u.Name).ToList(); 149 | using (var t = session.BeginTransaction()) 150 | { 151 | users.ForEach(u => session.Save(u)); 152 | t.Commit(); 153 | } 154 | 155 | var dbUsers = session2.QueryOver() 156 | .WhereRestrictionOn(u => u.Id).IsIn(users.Select(u => u.Id).ToArray()) 157 | .OrderBy(u => u.Name).Asc 158 | .List(); 159 | 160 | Assert.That(dbUsers, Has.Count.EqualTo(users.Count)); 161 | for (var i = 0; i < users.Count; i++) 162 | { 163 | Assert.That(dbUsers[i], Has.Property("Name").EqualTo(users[i].Name), "User " + i); 164 | Assert.That(dbUsers[i], Has.Property("Id").EqualTo(users[i].Id), "User " + i); 165 | var userProperties = dbUsers[i].Properties.ToList(); 166 | Assert.That(userProperties, Is.Not.Null, "User " + i + " Properties"); 167 | Assert.That(userProperties, Has.Count.EqualTo(1), "User " + i + " Properties"); 168 | Assert.That(userProperties[0], Has.Property("Name").EqualTo("Name"), "User " + i + " property 0"); 169 | Assert.That(userProperties[0], Has.Property("Value").EqualTo("Value"), "User " + i + " property 0"); 170 | } 171 | } 172 | } 173 | 174 | [Test] 175 | public void Select_a_scalar() 176 | { 177 | using (var session = CreateSession()) 178 | using (var session2 = CreateSession()) 179 | { 180 | var users = Builder.CreateListOfSize(100).Build().ToList(); 181 | using (var t = session.BeginTransaction()) 182 | { 183 | users.ForEach(u => session.Save(u)); 184 | t.Commit(); 185 | } 186 | 187 | var count = session2.QueryOver() 188 | .WhereRestrictionOn(x => x.Id) 189 | .IsIn(users.Select(x => x.Id).ToArray()) 190 | .RowCount(); 191 | 192 | Assert.That(count, Is.EqualTo(100)); 193 | } 194 | } 195 | 196 | [Test] 197 | public void Insert_and_update_an_entity() 198 | { 199 | using (var session = CreateSession()) 200 | using (var session2 = CreateSession()) 201 | { 202 | var user = new User { Name = "Name1" }; 203 | session.Save(user); 204 | session.Flush(); 205 | user.Name = "Name2"; 206 | session.Flush(); 207 | 208 | var userFromDb = session2.Get(user.Id); 209 | 210 | Assert.That(userFromDb.Name, Is.EqualTo("Name2")); 211 | } 212 | } 213 | 214 | [Test] 215 | public void Insert_and_update_multiple_entities() 216 | { 217 | using (var session = CreateSession()) 218 | using (var session2 = CreateSession()) 219 | { 220 | var users = Builder.CreateListOfSize(100).Build().ToList(); 221 | using (var t = session.BeginTransaction()) 222 | { 223 | users.ForEach(u => session.Save(u)); 224 | t.Commit(); 225 | } 226 | foreach (var u in users) 227 | { 228 | u.Name += "_2_"; 229 | } 230 | session.Flush(); 231 | 232 | var dbUsers = session2.QueryOver() 233 | .WhereRestrictionOn(u => u.Id).IsIn(users.Select(u => u.Id).ToArray()) 234 | .OrderBy(u => u.Name).Asc 235 | .List(); 236 | 237 | Assert.That(dbUsers, Has.Count.EqualTo(users.Count)); 238 | foreach (var u in dbUsers) 239 | { 240 | Assert.That(u.Name, Is.StringEnding("_2_")); 241 | } 242 | } 243 | } 244 | } 245 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/TransientErrorDetectionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Reflection; 4 | using System.Runtime.Serialization; 5 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 6 | using NHibernate.Driver; 7 | using NHibernate.Exceptions; 8 | using NHibernate.SqlAzure.RetryStrategies; 9 | using NHibernate.SqlAzure.Tests.Config; 10 | using NUnit.Framework; 11 | 12 | namespace NHibernate.SqlAzure.Tests 13 | { 14 | [TestFixture] 15 | internal class SqlAzureTransientErrorDetectionStrategyWithTimeoutsShould : 16 | PooledNHibernateTestBase 17 | { 18 | [Test] 19 | public void Retry_when_timeout_occurs() 20 | { 21 | try 22 | { 23 | using (var session = CreateSession()) 24 | { 25 | session.CreateSQLQuery(@"WAITFOR DELAY '00:02'").SetTimeout(1).ExecuteUpdate(); 26 | } 27 | } 28 | catch (Exception e) 29 | { 30 | Assert.That(new SqlAzureTransientErrorDetectionStrategyWithTimeouts().IsTransient(e)); 31 | return; 32 | } 33 | Assert.Fail("No timeout exception was thrown!"); 34 | } 35 | 36 | [Test] 37 | public void Mark_unwrapped_timeout_exception_as_transient([Values(-2, 121)] int errorCode) 38 | { 39 | var e = SqlExceptionGenerator.GetSqlException(errorCode); 40 | 41 | Assert.That(new SqlAzureTransientErrorDetectionStrategyWithTimeouts().IsTransient(e)); 42 | } 43 | 44 | [Test] 45 | public void Mark_wrapped_timeout_exception_as_transient([Values(-2, 121)] int errorCode) 46 | { 47 | var e = new GenericADOException("Wrapped exception", SqlExceptionGenerator.GetSqlException(errorCode)); 48 | 49 | Assert.That(new SqlAzureTransientErrorDetectionStrategyWithTimeouts().IsTransient(e)); 50 | } 51 | 52 | [Test] 53 | public void Mark_timeout_exception_as_transient() 54 | { 55 | var e = new TimeoutException(); 56 | 57 | Assert.That(new SqlAzureTransientErrorDetectionStrategyWithTimeouts().IsTransient(e)); 58 | } 59 | } 60 | 61 | [TestFixture(typeof(SqlAzureTransientErrorDetectionStrategy))] 62 | [TestFixture(typeof(SqlAzureTransientErrorDetectionStrategyWithTimeouts))] 63 | class TransientErrorDetectionStrategyShould : PooledNHibernateTestBase 64 | where TTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy, new() 65 | { 66 | [Test] 67 | public void Mark_unwrapped_exceptions_as_transient() 68 | { 69 | var e = SqlExceptionGenerator.GetSqlException(40197); 70 | 71 | Assert.That(new TTransientErrorDetectionStrategy().IsTransient(e)); 72 | } 73 | 74 | [Test] 75 | public void Mark_nhibernate_adonet_wrapped_exceptions_as_transient() 76 | { 77 | var e = new GenericADOException("Wrapped exception", SqlExceptionGenerator.GetSqlException(40197)); 78 | 79 | Assert.That(new TTransientErrorDetectionStrategy().IsTransient(e)); 80 | } 81 | 82 | [Test] 83 | public void Mark_nhibernate_transaction_wrapped_exceptions_as_transient() 84 | { 85 | var e = new TransactionException("Wrapped exception", SqlExceptionGenerator.GetSqlException(40197)); 86 | 87 | Assert.That(new TTransientErrorDetectionStrategy().IsTransient(e)); 88 | } 89 | 90 | [Test] 91 | public void Mark_nhibernate_invalid_operation_exception_wrapped_exceptions_as_transient() 92 | { 93 | var e = new InvalidOperationException("Lazy load error", new GenericADOException("Wrapped exception", SqlExceptionGenerator.GetSqlException(40197))); 94 | 95 | Assert.That(new TTransientErrorDetectionStrategy().IsTransient(e)); 96 | } 97 | } 98 | 99 | internal static class SqlExceptionGenerator 100 | { 101 | public static SqlException GetSqlException(int errorCode) 102 | { 103 | var collection = (SqlErrorCollection)Activator.CreateInstance(typeof(SqlErrorCollection), true); 104 | var error = (SqlError)Activator.CreateInstance(typeof(SqlError), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { errorCode, (byte)2, (byte)3, "server name", "error message", "proc", 100 }, null); 105 | 106 | typeof(SqlErrorCollection) 107 | .GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance) 108 | .Invoke(collection, new object[] { error }); 109 | 110 | return typeof(SqlException) 111 | .GetMethod("CreateException", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(SqlErrorCollection), typeof(string) }, null) 112 | .Invoke(null, new object[] { collection, "7.0.0" }) as SqlException; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2010 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHibernate.SqlAzure", "NHibernate.SqlAzure\NHibernate.SqlAzure.csproj", "{C51908DF-FAEA-4EAA-8F75-096346537C33}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{9C23CAA3-08A2-498A-AB98-F803AC42C49E}" 9 | ProjectSection(SolutionItems) = preProject 10 | BREAKING_CHANGES.md = BREAKING_CHANGES.md 11 | LICENSE = LICENSE 12 | logo.png = logo.png 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHibernate.SqlAzure.Tests", "NHibernate.SqlAzure.Tests\NHibernate.SqlAzure.Tests.csproj", "{887FD0A4-B8E0-4B3D-BF7E-4CC7090EB829}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHibernate4.SqlAzure", "NHibernate4.SqlAzure\NHibernate4.SqlAzure.csproj", "{BF649532-3E8A-4DC7-9F43-9AB25E475BF8}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHibernate4.SqlAzure.Tests", "NHibernate4.SqlAzure.Tests\NHibernate4.SqlAzure.Tests.csproj", "{4864689E-5B40-4EA2-A797-63B2AEBFE5DC}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHibernate5.SqlAzure", "NHibernate5.SqlAzure\NHibernate5.SqlAzure.csproj", "{895B6F59-B5BE-4796-847D-C3FF2C7EED66}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHibernate5.SqlAzure.Tests", "NHibernate5.SqlAzure.Tests\NHibernate5.SqlAzure.Tests.csproj", "{BF71D707-D321-40DB-97CB-3A3A02F345D5}" 25 | EndProject 26 | Global 27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 28 | Debug|Any CPU = Debug|Any CPU 29 | Release|Any CPU = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {C51908DF-FAEA-4EAA-8F75-096346537C33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {C51908DF-FAEA-4EAA-8F75-096346537C33}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {C51908DF-FAEA-4EAA-8F75-096346537C33}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {C51908DF-FAEA-4EAA-8F75-096346537C33}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {887FD0A4-B8E0-4B3D-BF7E-4CC7090EB829}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {887FD0A4-B8E0-4B3D-BF7E-4CC7090EB829}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {887FD0A4-B8E0-4B3D-BF7E-4CC7090EB829}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {887FD0A4-B8E0-4B3D-BF7E-4CC7090EB829}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {BF649532-3E8A-4DC7-9F43-9AB25E475BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {BF649532-3E8A-4DC7-9F43-9AB25E475BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {BF649532-3E8A-4DC7-9F43-9AB25E475BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {BF649532-3E8A-4DC7-9F43-9AB25E475BF8}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {4864689E-5B40-4EA2-A797-63B2AEBFE5DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {4864689E-5B40-4EA2-A797-63B2AEBFE5DC}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {4864689E-5B40-4EA2-A797-63B2AEBFE5DC}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {4864689E-5B40-4EA2-A797-63B2AEBFE5DC}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {895B6F59-B5BE-4796-847D-C3FF2C7EED66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {895B6F59-B5BE-4796-847D-C3FF2C7EED66}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {895B6F59-B5BE-4796-847D-C3FF2C7EED66}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {895B6F59-B5BE-4796-847D-C3FF2C7EED66}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {BF71D707-D321-40DB-97CB-3A3A02F345D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {BF71D707-D321-40DB-97CB-3A3A02F345D5}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {BF71D707-D321-40DB-97CB-3A3A02F345D5}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {BF71D707-D321-40DB-97CB-3A3A02F345D5}.Release|Any CPU.Build.0 = Release|Any CPU 56 | EndGlobalSection 57 | GlobalSection(SolutionProperties) = preSolution 58 | HideSolutionNode = FALSE 59 | EndGlobalSection 60 | GlobalSection(ExtensibilityGlobals) = postSolution 61 | SolutionGuid = {A2187D5F-03DE-4CF8-A458-16694FC9F9D6} 62 | EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45 63 | EndGlobalSection 64 | EndGlobal 65 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/DefaultReliableSql2008ClientDriver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; 3 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 4 | 5 | namespace NHibernate.SqlAzure 6 | { 7 | /// 8 | /// Default retry logic implementation for a that allows you to 9 | /// specify the transient error detection strategy. 10 | /// 11 | /// The transient error detection strategy you want to use 12 | public abstract class DefaultReliableSql2008ClientDriver : ReliableSql2008ClientDriver 13 | where TTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy, new() 14 | { 15 | protected override ReliableSqlConnection CreateReliableConnection() 16 | { 17 | const string incremental = "Incremental Retry Strategy"; 18 | const string backoff = "Backoff Retry Strategy"; 19 | var connectionRetry = new ExponentialBackoff(backoff, 10, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(10), false); 20 | var commandRetry = new Incremental(incremental, 10, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); 21 | 22 | var connection = new ReliableSqlConnection(null, 23 | new RetryPolicy(connectionRetry), 24 | new RetryPolicy(commandRetry) 25 | ); 26 | connection.ConnectionRetryPolicy.Retrying += ConnectionRetryEventHandler(); 27 | connection.CommandRetryPolicy.Retrying += CommandRetryEventHandler(); 28 | return connection; 29 | } 30 | 31 | /// 32 | /// An event handler delegate which will be called on connection retries. 33 | /// Only override this if you want to explicitly capture connection retries, otherwise override RetryEventHandler 34 | /// 35 | /// A custom method for handling the retry events 36 | protected virtual EventHandler ConnectionRetryEventHandler() 37 | { 38 | return RetryEventHandler(); 39 | } 40 | 41 | /// 42 | /// An event handler delegate which will be called on command retries. 43 | /// Only override this if you want to explicitly capture command retries, otherwise override RetryEventHandler 44 | /// 45 | /// A custom method for handling the retry events 46 | protected virtual EventHandler CommandRetryEventHandler() 47 | { 48 | return RetryEventHandler(); 49 | } 50 | 51 | /// 52 | /// An event handler delegate which will be called on connection and command retries. 53 | /// If you override ConnectionRetryEventHandler and CommandRetryEventHandler then this is redundant. 54 | /// 55 | /// A custom method for handling the retry events 56 | protected virtual EventHandler RetryEventHandler() 57 | { 58 | return null; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/NHibernate.SqlAzure.Standalone.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | NHibernate.SqlAzure.Standalone 6 | 7 | 8 | 2.0.0 9 | 10 | 11 | Robert Moore, Matthew Davies 12 | 13 | 14 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 15 | Unlike NHibernate.SqlAzure, this library doesn't come with TransientFaultHandling IL-merged - instead it's a NuGet dependency. 16 | 17 | 18 | Please see https://github.com/MRCollective/NHibernate.SqlAzure/releases for release notes and https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/BREAKING_CHANGES.md for any breaking changes. 19 | 20 | 21 | https://github.com/MRCollective/NHibernate.SqlAzure 22 | 23 | 24 | https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/LICENSE 25 | 26 | 27 | https://raw.github.com/MRCollective/NHibernate.SqlAzure/master/logo.png 28 | 29 | 30 | nhibernate, azure, sql, sql azure, transient 31 | 32 | 33 | en-US 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/NHibernate.SqlAzure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {C51908DF-FAEA-4EAA-8F75-096346537C33} 9 | Library 10 | Properties 11 | NHibernate.SqlAzure 12 | NHibernate.SqlAzure 13 | v4.5 14 | 512 15 | ..\ 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | bin\Debug\NHibernate.SqlAzure.XML 27 | false 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | bin\Release\NHibernate.SqlAzure.XML 37 | false 38 | 39 | 40 | false 41 | 42 | 43 | 44 | False 45 | ..\packages\Iesi.Collections.3.2.0.4000\lib\Net35\Iesi.Collections.dll 46 | 47 | 48 | False 49 | ..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll 50 | 51 | 52 | False 53 | ..\packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll 54 | 55 | 56 | False 57 | ..\packages\NHibernate.3.3.3.4001\lib\Net35\NHibernate.dll 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Component 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Designer 91 | 92 | 93 | Designer 94 | 95 | 96 | 97 | 98 | 99 | mkdir "$(TargetDir)Combined" 100 | "$(ProjectDir)..\packages\ilmerge.2.14.1208\tools\ILMerge.exe" /v4 /target:library "$(TargetPath)" "$(TargetDir)Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll" "$(TargetDir)Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll" /out:"$(TargetDir)Combined\NHibernate.SqlAzure.dll" 101 | copy "$(TargetDir)NHibernate.SqlAzure.XML" "$(TargetDir)Combined\NHibernate.SqlAzure.XML" 102 | 103 | 110 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/NHibernate.SqlAzure.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | NHibernate.SqlAzure 6 | 7 | 8 | 2.0.0 9 | 10 | 11 | Robert Moore, Matthew Davies 12 | 13 | 14 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 15 | This package has the Microsoft Transient Fault Handling library IL-merged into it; for a version that doesn't see the NHibernate.SqlAzure.Standalone package. 16 | 17 | 18 | Please see https://github.com/MRCollective/NHibernate.SqlAzure/releases for release notes and https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/BREAKING_CHANGES.md for any breaking changes. 19 | 20 | 21 | https://github.com/MRCollective/NHibernate.SqlAzure 22 | 23 | 24 | https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/LICENSE 25 | 26 | 27 | https://raw.github.com/MRCollective/NHibernate.SqlAzure/master/logo.png 28 | 29 | 30 | nhibernate, azure, sql, sql azure, transient 31 | 32 | 33 | en-US 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NHibernate.SqlAzure")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NHibernate.SqlAzure")] 13 | [assembly: AssemblyCopyright("Copyright © 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("cadcf8f5-3d8f-4949-937f-60d2acba588e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableAdoNetTransactionFactory.cs: -------------------------------------------------------------------------------- 1 | using NHibernate.Engine; 2 | using NHibernate.Engine.Transaction; 3 | using NHibernate.Transaction; 4 | 5 | namespace NHibernate.SqlAzure 6 | { 7 | /// 8 | /// An NHibernate transaction factory that provides retry logic for transient errors when executing transactions. 9 | /// 10 | /// 11 | /// Requires the connection to be a 12 | /// 13 | public class ReliableAdoNetTransactionFactory : AdoNetTransactionFactory, ITransactionFactory 14 | { 15 | public new ITransaction CreateTransaction(ISessionImplementor session) 16 | { 17 | return new ReliableAdoTransaction(session); 18 | } 19 | 20 | /// 21 | /// Executes some work in isolation. 22 | /// 23 | /// The NHibernate session 24 | /// The work to execute 25 | /// Whether or not to wrap the work in a transaction 26 | public new void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, bool transacted) 27 | { 28 | var connection = (ReliableSqlDbConnection)session.Connection; 29 | 30 | ReliableAdoTransaction.ExecuteWithRetry(connection, 31 | () => base.ExecuteWorkInIsolation(session, work, transacted) 32 | ); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableAdoNetWithDistributedTransactionFactory.cs: -------------------------------------------------------------------------------- 1 | using NHibernate.Engine; 2 | using NHibernate.Engine.Transaction; 3 | using NHibernate.Transaction; 4 | 5 | namespace NHibernate.SqlAzure 6 | { 7 | /// 8 | /// An NHibernate transaction factory that provides retry logic for transient errors when executing transactions. 9 | /// It is aware of Distributed Transactions. 10 | /// 11 | /// 12 | /// Requires the connection to be a 13 | /// 14 | public class ReliableAdoNetWithDistributedTransactionFactory : AdoNetWithDistributedTransactionFactory, ITransactionFactory 15 | { 16 | public new ITransaction CreateTransaction(ISessionImplementor session) 17 | { 18 | return new ReliableAdoTransaction(session); 19 | } 20 | 21 | /// 22 | /// Executes some work in isolation. 23 | /// 24 | /// The NHibernate session 25 | /// The work to execute 26 | /// Whether or not to wrap the work in a transaction 27 | public new void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, bool transacted) 28 | { 29 | var connection = (ReliableSqlDbConnection) session.Connection; 30 | 31 | ReliableAdoTransaction.ExecuteWithRetry(connection, 32 | () => base.ExecuteWorkInIsolation(session, work, transacted) 33 | ); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableAdoTransaction.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using NHibernate.Engine; 3 | using NHibernate.Transaction; 4 | 5 | namespace NHibernate.SqlAzure 6 | { 7 | /// 8 | /// Provides a transaction implementation that includes transient fault-handling retry logic. 9 | /// 10 | public class ReliableAdoTransaction : AdoTransaction, ITransaction 11 | { 12 | private readonly ISessionImplementor _session; 13 | 14 | /// 15 | /// Constructs a . 16 | /// 17 | /// NHibernate session to use. 18 | public ReliableAdoTransaction(ISessionImplementor session) : base(session) 19 | { 20 | _session = session; 21 | } 22 | 23 | public new void Begin() 24 | { 25 | Begin(IsolationLevel.Unspecified); 26 | } 27 | 28 | public new void Begin(IsolationLevel isolationLevel) 29 | { 30 | ExecuteWithRetry(_session.Connection as ReliableSqlDbConnection, () => base.Begin(isolationLevel)); 31 | } 32 | 33 | /// 34 | /// Executes the given action with the command retry policy on the given . 35 | /// 36 | /// The reliable connection 37 | /// The action to execute 38 | public static void ExecuteWithRetry(ReliableSqlDbConnection connection, System.Action action) 39 | { 40 | connection.ReliableConnection.CommandRetryPolicy.ExecuteAction(() => 41 | { 42 | if (connection.State != ConnectionState.Open) 43 | connection.Open(); 44 | 45 | action(); 46 | } 47 | ); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableSql2008ClientDriver.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; 3 | using NHibernate.AdoNet; 4 | using NHibernate.Driver; 5 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 6 | 7 | namespace NHibernate.SqlAzure 8 | { 9 | /// 10 | /// Abstract base class that enables the creation of an NHibernate client driver that extends the Sql 2008 driver, 11 | /// but adds in transient fault handling retry logic via . 12 | /// 13 | public abstract class ReliableSql2008ClientDriver : Sql2008ClientDriver, IEmbeddedBatcherFactoryProvider 14 | { 15 | /// 16 | /// Provides a instance to use for connections. 17 | /// 18 | /// A reliable connection 19 | protected abstract ReliableSqlConnection CreateReliableConnection(); 20 | 21 | /// 22 | /// Creates an uninitialized object for the SqlClientDriver. 23 | /// 24 | /// 25 | /// An unitialized object. 26 | /// 27 | public override IDbConnection CreateConnection() 28 | { 29 | return new ReliableSqlDbConnection(CreateReliableConnection()); 30 | } 31 | 32 | /// 33 | /// Creates an uninitialized object for the SqlClientDriver. 34 | /// 35 | /// 36 | /// An unitialized object. 37 | /// 38 | public override IDbCommand CreateCommand() 39 | { 40 | return new ReliableSqlCommand(); 41 | } 42 | 43 | /// 44 | /// Returns the class to use for the Batcher Factory. 45 | /// 46 | public System.Type BatcherFactoryClass 47 | { 48 | get { return typeof(ReliableSqlClientBatchingBatcherFactory); } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableSqlClientBatchingBatcher.cs: -------------------------------------------------------------------------------- 1 | // Parts of this file were copied from NHibernate.AdoNet.SqlClientBatchingBatcherFactory, but modified to use ReliableSqlDbConnection 2 | // The #regions indicate the copied code 3 | using System; 4 | using System.Data; 5 | using System.Data.Common; 6 | using System.Reflection; 7 | using System.Text; 8 | using NHibernate.AdoNet; 9 | using NHibernate.AdoNet.Util; 10 | using NHibernate.Exceptions; 11 | 12 | namespace NHibernate.SqlAzure 13 | { 14 | /// 15 | /// Exposes functionality when a 16 | /// connection is being used. 17 | /// 18 | public class ReliableSqlClientBatchingBatcher : SqlClientBatchingBatcher 19 | { 20 | #region Impersonate private fields in base class 21 | private readonly ConnectionManager _connectionManager; 22 | private readonly FieldInfo _totalExpectedRowsAffectedField = typeof(SqlClientBatchingBatcher) 23 | .GetField("_totalExpectedRowsAffected", BindingFlags.NonPublic | BindingFlags.Instance); 24 | private readonly FieldInfo _currentBatchField = typeof (SqlClientBatchingBatcher) 25 | .GetField("_currentBatch", BindingFlags.NonPublic | BindingFlags.Instance); 26 | private readonly FieldInfo _currentBatchCommandsLogField = typeof(SqlClientBatchingBatcher) 27 | .GetField("_currentBatchCommandsLog", BindingFlags.NonPublic | BindingFlags.Instance); 28 | private readonly MethodInfo _createConfiguredBatchMethod = typeof (SqlClientBatchingBatcher) 29 | .GetMethod("CreateConfiguredBatch", BindingFlags.Instance | BindingFlags.NonPublic); 30 | 31 | // ReSharper disable InconsistentNaming 32 | private int _totalExpectedRowsAffected 33 | { 34 | get { return (int)_totalExpectedRowsAffectedField.GetValue(this); } 35 | set { _totalExpectedRowsAffectedField.SetValue(this, value); } 36 | } 37 | private SqlClientSqlCommandSet _currentBatch 38 | { 39 | get { return (SqlClientSqlCommandSet)_currentBatchField.GetValue(this); } 40 | set { _currentBatchField.SetValue(this, value); } 41 | } 42 | private StringBuilder _currentBatchCommandsLog 43 | { 44 | get { return (StringBuilder) _currentBatchCommandsLogField.GetValue(this); } 45 | set { _currentBatchCommandsLogField.SetValue(this, value); } 46 | } 47 | private int _batchSize 48 | { 49 | get { return BatchSize; } 50 | } 51 | // ReSharper restore InconsistentNaming 52 | 53 | private SqlClientSqlCommandSet CreateConfiguredBatch() 54 | { 55 | return (SqlClientSqlCommandSet)_createConfiguredBatchMethod.Invoke(this, null); 56 | } 57 | 58 | public ReliableSqlClientBatchingBatcher(ConnectionManager connectionManager, IInterceptor interceptor) 59 | : base(connectionManager, interceptor) 60 | { 61 | _connectionManager = connectionManager; 62 | } 63 | #endregion 64 | 65 | public override void AddToBatch(IExpectation expectation) 66 | { 67 | #region NHibernate code 68 | _totalExpectedRowsAffected += expectation.ExpectedRowCount; 69 | IDbCommand batchUpdate = CurrentCommand; 70 | Driver.AdjustCommand(batchUpdate); 71 | string lineWithParameters = null; 72 | var sqlStatementLogger = Factory.Settings.SqlStatementLogger; 73 | if (sqlStatementLogger.IsDebugEnabled || Log.IsDebugEnabled) 74 | { 75 | lineWithParameters = sqlStatementLogger.GetCommandLineWithParameters(batchUpdate); 76 | var formatStyle = sqlStatementLogger.DetermineActualStyle(FormatStyle.Basic); 77 | lineWithParameters = formatStyle.Formatter.Format(lineWithParameters); 78 | _currentBatchCommandsLog.Append("command ") 79 | .Append(_currentBatch.CountOfCommands) 80 | .Append(":") 81 | .AppendLine(lineWithParameters); 82 | } 83 | if (Log.IsDebugEnabled) 84 | { 85 | Log.Debug("Adding to batch:" + lineWithParameters); 86 | } 87 | #endregion 88 | _currentBatch.Append((System.Data.SqlClient.SqlCommand)(ReliableSqlCommand)batchUpdate); 89 | #region NHibernate code 90 | if (_currentBatch.CountOfCommands >= _batchSize) 91 | { 92 | ExecuteBatchWithTiming(batchUpdate); 93 | } 94 | #endregion 95 | } 96 | 97 | // Need this method call in this class rather than the base class to ensure Prepare is called... if only it was virtual :( 98 | protected void ExecuteBatch(IDbCommand ps) 99 | { 100 | #region NHibernate code 101 | Log.DebugFormat("Executing batch"); 102 | CheckReaders(); 103 | Prepare(_currentBatch.BatchCommand); 104 | if (Factory.Settings.SqlStatementLogger.IsDebugEnabled) 105 | { 106 | Factory.Settings.SqlStatementLogger.LogBatchCommand(_currentBatchCommandsLog.ToString()); 107 | _currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:"); 108 | } 109 | 110 | int rowsAffected; 111 | try 112 | { 113 | rowsAffected = _currentBatch.ExecuteNonQuery(); 114 | } 115 | catch (DbException e) 116 | { 117 | throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not execute batch command."); 118 | } 119 | 120 | Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, rowsAffected); 121 | 122 | _currentBatch.Dispose(); 123 | _totalExpectedRowsAffected = 0; 124 | _currentBatch = CreateConfiguredBatch(); 125 | #endregion 126 | } 127 | 128 | /// 129 | /// Prepares the for execution in the database. 130 | /// 131 | /// 132 | /// This takes care of hooking the up to an 133 | /// and if one exists. It will call Prepare if the Driver 134 | /// supports preparing commands. 135 | /// 136 | protected new void Prepare(IDbCommand cmd) 137 | { 138 | try 139 | { 140 | var sessionConnection = (ReliableSqlDbConnection)_connectionManager.GetConnection(); 141 | 142 | #region NHibernate code 143 | if (cmd.Connection != null) 144 | { 145 | // make sure the commands connection is the same as the Sessions connection 146 | // these can be different when the session is disconnected and then reconnected 147 | if (cmd.Connection != sessionConnection) 148 | { 149 | cmd.Connection = (System.Data.SqlClient.SqlConnection) sessionConnection; 150 | } 151 | } 152 | else 153 | { 154 | cmd.Connection = (System.Data.SqlClient.SqlConnection) sessionConnection; 155 | } 156 | 157 | _connectionManager.Transaction.Enlist(cmd); 158 | Driver.PrepareCommand(cmd); 159 | #endregion 160 | } 161 | catch (InvalidOperationException ioe) 162 | { 163 | #region NHibernate code 164 | throw new ADOException("While preparing " + cmd.CommandText + " an error occurred", ioe); 165 | #endregion 166 | } 167 | } 168 | 169 | protected override void DoExecuteBatch(IDbCommand ps) 170 | { 171 | var connection = (ReliableSqlDbConnection)_connectionManager.GetConnection(); 172 | ReliableAdoTransaction.ExecuteWithRetry(connection, () => ExecuteBatch(ps)); 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableSqlClientBatchingBatcherFactory.cs: -------------------------------------------------------------------------------- 1 | // This file was copied from NHibernate.AdoNet.SqlClientBatchingBatcherFactory, but modified to use ReliableSqlClientBatchingBatcher 2 | using NHibernate.AdoNet; 3 | using NHibernate.Engine; 4 | 5 | namespace NHibernate.SqlAzure 6 | { 7 | /// 8 | /// An implementation that creates 9 | /// instances. 10 | /// 11 | public class ReliableSqlClientBatchingBatcherFactory : IBatcherFactory 12 | { 13 | /// 14 | /// Creates the batcher. 15 | /// 16 | /// The connection manager 17 | /// The interceptor 18 | /// The instance 19 | public virtual IBatcher CreateBatcher(ConnectionManager connectionManager, IInterceptor interceptor) 20 | { 21 | return new ReliableSqlClientBatchingBatcher(connectionManager, interceptor); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableSqlCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; 4 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 5 | 6 | namespace NHibernate.SqlAzure 7 | { 8 | /// 9 | /// An implementation that wraps a object such that any 10 | /// queries that are executed are executed via a . 11 | /// 12 | /// 13 | /// Note: For this to work it requires that the Connection property be set with a object. 14 | /// 15 | public class ReliableSqlCommand : IDbCommand 16 | { 17 | /// 18 | /// The underlying being proxied. 19 | /// 20 | public System.Data.SqlClient.SqlCommand Current { get; private set; } 21 | 22 | /// 23 | /// The that has been assigned to the command via the Connection property. 24 | /// 25 | public ReliableSqlConnection ReliableConnection { get; set; } 26 | 27 | /// 28 | /// Constructs a . 29 | /// 30 | public ReliableSqlCommand() 31 | { 32 | Current = new System.Data.SqlClient.SqlCommand(); 33 | } 34 | 35 | /// 36 | /// Explicit type-casting between a and a . 37 | /// 38 | /// The being casted 39 | /// The underlying being proxied. 40 | public static explicit operator System.Data.SqlClient.SqlCommand(ReliableSqlCommand command) 41 | { 42 | return command.Current; 43 | } 44 | 45 | /// 46 | /// Returns the underlying and expects a when being set. 47 | /// 48 | public IDbConnection Connection 49 | { 50 | get { return Current.Connection; } 51 | set 52 | { 53 | ReliableConnection = ((ReliableSqlDbConnection)value).ReliableConnection; 54 | Current.Connection = ReliableConnection.Current; 55 | } 56 | } 57 | 58 | #region Wrapping code 59 | public void Dispose() 60 | { 61 | Current.Dispose(); 62 | } 63 | 64 | public void Prepare() 65 | { 66 | Current.Prepare(); 67 | } 68 | 69 | public void Cancel() 70 | { 71 | Current.Cancel(); 72 | } 73 | 74 | public IDbDataParameter CreateParameter() 75 | { 76 | return Current.CreateParameter(); 77 | } 78 | 79 | public int ExecuteNonQuery() 80 | { 81 | return ReliableConnection.ExecuteCommand(Current); 82 | } 83 | 84 | public IDataReader ExecuteReader() 85 | { 86 | return ReliableConnection.ExecuteCommand(Current); 87 | } 88 | 89 | public IDataReader ExecuteReader(CommandBehavior behavior) 90 | { 91 | return ReliableConnection.ExecuteCommand(Current, behavior); 92 | } 93 | 94 | public object ExecuteScalar() 95 | { 96 | return ReliableConnection.ExecuteCommand(Current); 97 | } 98 | 99 | public IDbTransaction Transaction 100 | { 101 | get { return Current.Transaction; } 102 | set { Current.Transaction = (SqlTransaction)value; } 103 | } 104 | 105 | public string CommandText 106 | { 107 | get { return Current.CommandText; } 108 | set { Current.CommandText = value; } 109 | } 110 | 111 | public int CommandTimeout 112 | { 113 | get { return Current.CommandTimeout; } 114 | set { Current.CommandTimeout = value; } 115 | } 116 | 117 | public CommandType CommandType 118 | { 119 | get { return Current.CommandType; } 120 | set { Current.CommandType = value; } 121 | } 122 | 123 | public IDataParameterCollection Parameters 124 | { 125 | get { return Current.Parameters; } 126 | } 127 | 128 | public UpdateRowSource UpdatedRowSource 129 | { 130 | get { return Current.UpdatedRowSource; } 131 | set { Current.UpdatedRowSource = value; } 132 | } 133 | #endregion 134 | } 135 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/ReliableSqlDbConnection.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.Common; 3 | using System.Data.SqlClient; 4 | using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; 5 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 6 | 7 | namespace NHibernate.SqlAzure 8 | { 9 | /// 10 | /// Wrap in a class that extends 11 | /// so internal type casts within NHibernate don't fail. 12 | /// 13 | public class ReliableSqlDbConnection : DbConnection 14 | { 15 | bool disposed = false; 16 | /// 17 | /// The underlying . 18 | /// 19 | public ReliableSqlConnection ReliableConnection { get; set; } 20 | 21 | /// 22 | /// Constructs a to wrap around the given . 23 | /// 24 | /// The to wrap 25 | public ReliableSqlDbConnection(ReliableSqlConnection connection) 26 | { 27 | ReliableConnection = connection; 28 | } 29 | 30 | /// 31 | /// Explicit type-casting between and . 32 | /// 33 | /// The being casted 34 | /// The underlying 35 | public static explicit operator SqlConnection(ReliableSqlDbConnection connection) 36 | { 37 | return connection.ReliableConnection.Current; 38 | } 39 | 40 | protected override void Dispose(bool disposing) { 41 | if (disposed) 42 | return; 43 | if (disposing) { 44 | ReliableConnection.Dispose(); 45 | } 46 | disposed = true; 47 | base.Dispose(disposing); 48 | } 49 | 50 | #region Wrapping code 51 | protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) 52 | { 53 | return (DbTransaction) ReliableConnection.BeginTransaction(isolationLevel); 54 | } 55 | 56 | public override void Close() 57 | { 58 | ReliableConnection.Close(); 59 | } 60 | 61 | public override DataTable GetSchema() 62 | { 63 | return ReliableConnection.ConnectionRetryPolicy.ExecuteAction ( 64 | () => ReliableConnection.Current.GetSchema() 65 | ); 66 | } 67 | 68 | public override DataTable GetSchema(string collectionName) 69 | { 70 | return ReliableConnection.ConnectionRetryPolicy.ExecuteAction ( 71 | () => ReliableConnection.Current.GetSchema(collectionName) 72 | ); 73 | } 74 | 75 | public override DataTable GetSchema(string collectionName, string[] restrictionValues) 76 | { 77 | return ReliableConnection.ConnectionRetryPolicy.ExecuteAction ( 78 | () => ReliableConnection.Current.GetSchema(collectionName, restrictionValues) 79 | ); 80 | } 81 | 82 | public override void ChangeDatabase(string databaseName) 83 | { 84 | ReliableConnection.ChangeDatabase(databaseName); 85 | } 86 | 87 | protected override DbCommand CreateDbCommand() 88 | { 89 | return ReliableConnection.CreateCommand(); 90 | } 91 | 92 | public override void Open() 93 | { 94 | ReliableConnection.Open(); 95 | } 96 | 97 | public override string ConnectionString { get { return ReliableConnection.ConnectionString; } set { ReliableConnection.ConnectionString = value; } } 98 | public override int ConnectionTimeout { get { return ReliableConnection.ConnectionTimeout; } } 99 | public override string Database { get { return ReliableConnection.Database; } } 100 | public override string DataSource { get { return ""; } } 101 | public override string ServerVersion { get { return ""; } } 102 | public override ConnectionState State { get { return ReliableConnection.State; } } 103 | #endregion 104 | } 105 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/RetryStrategies/SqlAzureTransientErrorDetectionStrategy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Linq; 4 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 5 | 6 | 7 | namespace NHibernate.SqlAzure.RetryStrategies 8 | { 9 | /// 10 | /// Transient error detection strategy for SQL Azure that is a copy of the Enterprise Library detection strategy. 11 | /// 12 | public class SqlAzureTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy 13 | { 14 | // From Enterprise Library 6 changelog (see https://entlib.codeplex.com/wikipage?title=EntLib6ReleaseNotes): 15 | // Error code 40540 from SQL Database added as a transient error (see http://msdn.microsoft.com/en-us/library/ff394106.aspx#bkmk_throt_errors). 16 | // Added error codes 10928 and 10929 from SQL Database as transient errors (see http://blogs.msdn.com/b/psssql/archive/2012/10/31/worker-thread-governance-coming-to-azure-sql-database.aspx). 17 | // Added error codes 4060, 40197, 40501, 40613 from MSDN documentation (see https://azure.microsoft.com/en-us/documentation/articles/sql-database-develop-error-messages/) 18 | 19 | private readonly int[] _errorNumbers = new int[] { 40540, 10928, 10929, 4060, 40197, 40501, 40613 }; 20 | 21 | private readonly SqlDatabaseTransientErrorDetectionStrategy _entLibStrategy = new SqlDatabaseTransientErrorDetectionStrategy(); 22 | 23 | public virtual bool IsTransient(Exception ex) 24 | { 25 | return IsTransientAzureException(ex); 26 | } 27 | 28 | private bool IsTransientAzureException(Exception ex) 29 | { 30 | if (ex == null) 31 | return false; 32 | 33 | return _entLibStrategy.IsTransient(ex) 34 | || IsNewTransientError(ex) 35 | || IsTransientAzureException(ex.InnerException); 36 | } 37 | 38 | private bool IsNewTransientError(Exception ex) 39 | { 40 | SqlException sqlException; 41 | return (sqlException = ex as SqlException) != null 42 | && sqlException.Errors.Cast().Any(error => _errorNumbers.Contains(error.Number)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/RetryStrategies/SqlAzureTransientErrorDetectionStrategyWithTimeouts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Linq; 4 | 5 | namespace NHibernate.SqlAzure.RetryStrategies 6 | { 7 | /// 8 | /// Transient error detection strategy for SQL Azure that extends the Enterprise Library detection strategy and also detects timeout exceptions. 9 | /// 10 | public class SqlAzureTransientErrorDetectionStrategyWithTimeouts : SqlAzureTransientErrorDetectionStrategy 11 | { 12 | public override bool IsTransient(Exception ex) 13 | { 14 | return base.IsTransient(ex) || IsTransientTimeout(ex); 15 | } 16 | 17 | protected virtual bool IsTransientTimeout(Exception ex) 18 | { 19 | if (IsConnectionTimeout(ex)) 20 | return true; 21 | 22 | return ex.InnerException != null && IsTransientTimeout(ex.InnerException); 23 | } 24 | 25 | protected virtual bool IsConnectionTimeout(Exception ex) 26 | { 27 | // Timeout exception: error code -2 28 | // http://social.msdn.microsoft.com/Forums/en-US/ssdsgetstarted/thread/7a50985d-92c2-472f-9464-a6591efec4b3/ 29 | 30 | // Timeout exception: error code 121 31 | // http://social.msdn.microsoft.com/Forums/nl-NL/ssdsgetstarted/thread/5e195f94-d4d2-4c2d-8a4e-7d66b4761510 32 | 33 | SqlException sqlException; 34 | return ex != null 35 | && (sqlException = ex as SqlException) != null 36 | && sqlException.Errors.Cast().Any(error => error.Number == -2 || error.Number == 121); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/SqlAzureClientDriver.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 2 | 3 | namespace NHibernate.SqlAzure 4 | { 5 | /// 6 | /// NHibernate client driver for SQL Azure that includes the Enterprise Library transient fault-handling. 7 | /// Note: It doesn't handle timeout errors, which can sometimes be transient. If you have timeout errors 8 | /// that aren't caused by unoptimised queries then use 9 | /// 10 | public class SqlAzureClientDriver : DefaultReliableSql2008ClientDriver {} 11 | } -------------------------------------------------------------------------------- /NHibernate.SqlAzure/SqlAzureClientDriverWithTimeoutRetries.cs: -------------------------------------------------------------------------------- 1 | using NHibernate.SqlAzure.RetryStrategies; 2 | 3 | namespace NHibernate.SqlAzure 4 | { 5 | /// 6 | /// NHibernate client driver for SQL Azure that includes the Enterprise Library transient fault-handling as well as timeout retries. 7 | /// Note: Timeout errors can be caused by unoptimised queries that you might be executing as well as being a transient exception. 8 | /// 9 | public class SqlAzureClientDriverWithTimeoutRetries : DefaultReliableSql2008ClientDriver {} 10 | } 11 | -------------------------------------------------------------------------------- /NHibernate.SqlAzure/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure.Tests/App.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure.Tests/NHibernate4.SqlAzure.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4864689E-5B40-4EA2-A797-63B2AEBFE5DC} 8 | Library 9 | Properties 10 | NHibernate4.SqlAzure.Tests 11 | NHibernate4.SqlAzure.Tests 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | ..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll 38 | 39 | 40 | ..\packages\FluentMigrator.1.1.2.1\lib\40\FluentMigrator.dll 41 | 42 | 43 | ..\packages\FluentMigrator.Runner.1.1.1.26\lib\NET40\FluentMigrator.Runner.dll 44 | 45 | 46 | False 47 | ..\packages\FluentNHibernate.2.0.1.0\lib\net40\FluentNHibernate.dll 48 | 49 | 50 | ..\packages\NHibernateProfiler.1.0.0.951\lib\Net40\HibernatingRhinos.Profiler.Appender.v4.0.dll 51 | 52 | 53 | ..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll 54 | 55 | 56 | ..\packages\NHibernate.4.1.0.4000\lib\net40\NHibernate.dll 57 | True 58 | 59 | 60 | ..\packages\NUnit.2.6.4\lib\nunit.framework.dll 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Designer 79 | true 80 | 81 | 82 | App.config 83 | True 84 | 85 | 86 | Designer 87 | 88 | 89 | 90 | 91 | {bf649532-3e8a-4dc7-9f43-9ab25e475bf8} 92 | NHibernate4.SqlAzure 93 | 94 | 95 | 96 | 97 | 98 | 99 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 100 | 101 | 102 | 103 | 110 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NHibernate4.SqlAzure.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NHibernate4.SqlAzure.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4864689e-5b40-4ea2-a797-63b2aebfe5dc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure/NHibernate4.SqlAzure.Standalone.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | NHibernate4.SqlAzure.Standalone 6 | 7 | 8 | 2.0.0 9 | 10 | 11 | Robert Moore, Matthew Davies 12 | 13 | 14 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 15 | Unlike NHibernate.SqlAzure, this library doesn't come with TransientFaultHandling IL-merged - instead it's a NuGet dependency. 16 | 17 | 18 | Please see https://github.com/MRCollective/NHibernate.SqlAzure/releases for release notes and https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/BREAKING_CHANGES.md for any breaking changes. 19 | 20 | 21 | https://github.com/MRCollective/NHibernate.SqlAzure 22 | 23 | 24 | https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/LICENSE 25 | 26 | 27 | https://raw.github.com/MRCollective/NHibernate.SqlAzure/master/logo.png 28 | 29 | 30 | nhibernate, azure, sql, sql azure, transient 31 | 32 | 33 | en-US 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure/NHibernate4.SqlAzure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BF649532-3E8A-4DC7-9F43-9AB25E475BF8} 8 | Library 9 | Properties 10 | NHibernate.SqlAzure 11 | NHibernate.SqlAzure 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | bin\Debug\NHibernate.SqlAzure.XML 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | bin\Release\NHibernate.SqlAzure.XML 33 | 34 | 35 | 36 | ..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll 37 | 38 | 39 | ..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll 40 | 41 | 42 | ..\packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll 43 | 44 | 45 | ..\packages\NHibernate.4.1.0.4000\lib\net40\NHibernate.dll 46 | True 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Designer 63 | 64 | 65 | Designer 66 | 67 | 68 | 69 | 70 | 71 | mkdir "$(TargetDir)Combined" 72 | "$(ProjectDir)..\packages\ilmerge.2.14.1208\tools\ILMerge.exe" /v4 /target:library "$(TargetPath)" "$(TargetDir)Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll" "$(TargetDir)Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll" /out:"$(TargetDir)Combined\NHibernate.SqlAzure.dll" 73 | copy "$(TargetDir)NHibernate.SqlAzure.XML" "$(TargetDir)Combined\NHibernate.SqlAzure.XML" 74 | 75 | 82 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure/NHibernate4.SqlAzure.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | NHibernate4.SqlAzure 6 | 7 | 8 | 2.0.0 9 | 10 | 11 | Robert Moore, Matthew Davies 12 | 13 | 14 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 15 | This package has the Microsoft Transient Fault Handling library IL-merged into it; for a version that doesn't see the NHibernate.SqlAzure.Standalone package. 16 | 17 | 18 | Please see https://github.com/MRCollective/NHibernate.SqlAzure/releases for release notes and https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/BREAKING_CHANGES.md for any breaking changes. 19 | 20 | 21 | https://github.com/MRCollective/NHibernate.SqlAzure 22 | 23 | 24 | https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/LICENSE 25 | 26 | 27 | https://raw.github.com/MRCollective/NHibernate.SqlAzure/master/logo.png 28 | 29 | 30 | nhibernate, azure, sql, sql azure, transient 31 | 32 | 33 | en-US 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NHibernate4.SqlAzure")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NHibernate4.SqlAzure")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bf649532-3e8a-4dc7-9f43-9ab25e475bf8")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /NHibernate4.SqlAzure/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/App.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/App_Start/NHibernateProfilerBootstrapper.cs: -------------------------------------------------------------------------------- 1 | using HibernatingRhinos.Profiler.Appender.NHibernate; 2 | 3 | // If you're using .NET Core please remove this line and call NHibernateProfiler.Initialize(); on the very beginning of your application. 4 | [assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NHibernate5.SqlAzure.Tests.App_Start.NHibernateProfilerBootstrapper), "PreStart")] 5 | namespace NHibernate5.SqlAzure.Tests.App_Start 6 | { 7 | public static class NHibernateProfilerBootstrapper 8 | { 9 | public static void PreStart() 10 | { 11 | // Initialize the profiler 12 | NHibernateProfiler.Initialize(); 13 | 14 | // You can also use the profiler in an offline manner. 15 | // This will generate a file with a snapshot of all the NHibernate activity in the application, 16 | // which you can use for later analysis by loading the file into the profiler. 17 | // var filename = @"c:\profiler-log"; 18 | // NHibernateProfiler.InitializeOfflineProfiling(filename); 19 | 20 | // You can use the following for production profiling. 21 | // NHibernateProfiler.InitializeForProduction(11234, "A strong password like: ze38r/b2ulve2HLQB8NK5AYig"); 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/App_Start/NHibernateProfilerBootstrapper.vb: -------------------------------------------------------------------------------- 1 | Imports HibernatingRhinos.Profiler.Appender.NHibernate 2 | 3 | ' If you're using .NET Core please remove this line and call NHibernateProfiler.Initialize() on the very beginning of your application. 4 | 5 | Namespace App_Start 6 | Public Class NHibernateProfilerBootstrapper 7 | Public Shared Sub PreStart() 8 | ' Initialize the profiler 9 | NHibernateProfiler.Initialize() 10 | 11 | ' You can also use the profiler in an offline manner. 12 | ' This will generate a file with a snapshot of all the NHibernate activity in the application, 13 | ' which you can use for later analysis by loading the file into the profiler. 14 | ' Dim FileName as String = @"c:\profiler-log"; 15 | ' NHibernateProfiler.InitializeOfflineProfiling(FileName) 16 | 17 | ' You can use the following for production profiling. 18 | ' NHibernateProfiler.InitializeForProduction(11234, "A strong password like: ze38r/b2ulve2HLQB8NK5AYig"); 19 | End Sub 20 | End Class 21 | End Namespace 22 | 23 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/NHibernate5.SqlAzure.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {BF71D707-D321-40DB-97CB-3A3A02F345D5} 7 | Library 8 | Properties 9 | NHibernate5.SqlAzure.Tests 10 | NHibernate5.SqlAzure.Tests 11 | v4.6.1 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 15.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE 28 | prompt 29 | 4 30 | 31 | 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | 41 | ..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll 42 | 43 | 44 | ..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll 45 | 46 | 47 | ..\packages\FluentMigrator.1.1.2.1\lib\40\FluentMigrator.dll 48 | 49 | 50 | ..\packages\FluentMigrator.Runner.1.1.1.26\lib\NET40\FluentMigrator.Runner.dll 51 | 52 | 53 | ..\packages\FluentNHibernate.2.0.3.0\lib\net40\FluentNHibernate.dll 54 | 55 | 56 | ..\packages\NHibernateProfiler.5.0.5044\lib\net46\HibernatingRhinos.Profiler.Appender.dll 57 | 58 | 59 | ..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll 60 | 61 | 62 | 63 | ..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll 64 | 65 | 66 | ..\packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll 67 | 68 | 69 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 70 | 71 | 72 | ..\packages\NHibernate.5.2.3\lib\net461\NHibernate.dll 73 | 74 | 75 | ..\packages\NUnit.2.6.2\lib\nunit.framework.dll 76 | 77 | 78 | ..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll 79 | 80 | 81 | ..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | ..\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll 90 | 91 | 92 | 93 | 94 | 95 | ..\packages\WebActivator.1.4.4\lib\net40\WebActivator.dll 96 | 97 | 98 | ..\packages\WebActivatorEx.2.0.5\lib\net40\WebActivatorEx.dll 99 | 100 | 101 | 102 | 103 | FluentRunner.cs 104 | 105 | 106 | LocalTestingReliableSql2008ClientDriver.cs 107 | 108 | 109 | NHibernateConfiguration.cs 110 | 111 | 112 | NHibernateTestBase.cs 113 | 114 | 115 | SqlExpressTransientErrorDetectionStrategy.cs 116 | 117 | 118 | ConnectionTests.cs 119 | 120 | 121 | User.cs 122 | 123 | 124 | UserProperty.cs 125 | 126 | 127 | 20120801141148_CreateUserTable.cs 128 | 129 | 130 | 20120809201500_CreateUserPropertyTable.cs 131 | 132 | 133 | SqlClientDriverTests.cs 134 | 135 | 136 | TransientErrorDetectionTests.cs 137 | 138 | 139 | 140 | 141 | 142 | 143 | Designer 144 | true 145 | 146 | 147 | App.config 148 | True 149 | 150 | 151 | Designer 152 | 153 | 154 | 155 | 156 | {895b6f59-b5be-4796-847d-c3ff2c7eed66} 157 | NHibernate5.SqlAzure 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("NHibernate5.SqlAzure.Tests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("NHibernate5.SqlAzure.Tests")] 10 | [assembly: AssemblyCopyright("Copyright © 2018")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("bf71d707-d321-40db-97cb-3a3a02f345d5")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/NHibernate5.SqlAzure.Standalone.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | NHibernate5.SqlAzure.Standalone 6 | 7 | 8 | 2.0.0 9 | 10 | 11 | Robert Moore, Matthew Davies 12 | 13 | 14 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 15 | Unlike NHibernate.SqlAzure, this library doesn't come with TransientFaultHandling IL-merged - instead it's a NuGet dependency. 16 | 17 | 18 | Please see https://github.com/MRCollective/NHibernate.SqlAzure/releases for release notes and https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/BREAKING_CHANGES.md for any breaking changes. 19 | 20 | 21 | https://github.com/MRCollective/NHibernate.SqlAzure 22 | 23 | 24 | https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/LICENSE 25 | 26 | 27 | https://raw.github.com/MRCollective/NHibernate.SqlAzure/master/logo.png 28 | 29 | 30 | nhibernate, azure, sql, sql azure, transient 31 | 32 | 33 | en-US 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/NHibernate5.SqlAzure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {895B6F59-B5BE-4796-847D-C3FF2C7EED66} 8 | Library 9 | Properties 10 | NHibernate.SqlAzure 11 | NHibernate.SqlAzure 12 | v4.6.1 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | bin\Debug\NHibernate.SqlAzure.xml 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | bin\Release\NHibernate.SqlAzure.xml 33 | 34 | 35 | 36 | ..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll 37 | 38 | 39 | ..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll 40 | 41 | 42 | ..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll 43 | 44 | 45 | ..\packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll 46 | 47 | 48 | ..\packages\NHibernate.5.2.3\lib\net461\NHibernate.dll 49 | 50 | 51 | ..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll 52 | 53 | 54 | ..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | DefaultReliableSql2008ClientDriver.cs 71 | 72 | 73 | ReliableAdoNetTransactionFactory.cs 74 | 75 | 76 | ReliableAdoTransaction.cs 77 | 78 | 79 | ReliableSqlClientBatchingBatcherFactory.cs 80 | 81 | 82 | ReliableSqlDbConnection.cs 83 | Component 84 | 85 | 86 | SqlAzureTransientErrorDetectionStrategy.cs 87 | 88 | 89 | SqlAzureTransientErrorDetectionStrategyWithTimeouts.cs 90 | 91 | 92 | SqlAzureClientDriver.cs 93 | 94 | 95 | SqlAzureClientDriverWithTimeoutRetries.cs 96 | 97 | 98 | 99 | 100 | 101 | 102 | Component 103 | 104 | 105 | 106 | 107 | Designer 108 | 109 | 110 | Designer 111 | 112 | 113 | 114 | 115 | 116 | mkdir "$(TargetDir)Combined" 117 | "$(ProjectDir)..\packages\ilmerge.2.14.1208\tools\ILMerge.exe" /log:log.txt /v4 /target:library "$(TargetPath)" "$(TargetDir)Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll" "$(TargetDir)Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Data.dll" /out:"$(TargetDir)Combined\NHibernate.SqlAzure.dll" 118 | copy "$(TargetDir)NHibernate.SqlAzure.XML" "$(TargetDir)Combined\NHibernate.SqlAzure.XML" 119 | 120 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/NHibernate5.SqlAzure.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | NHibernate5.SqlAzure 6 | 7 | 8 | 2.0.0 9 | 10 | 11 | Robert Moore, Matthew Davies 12 | 13 | 14 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 15 | This package has the Microsoft Transient Fault Handling library IL-merged into it; for a version that doesn't see the NHibernate.SqlAzure.Standalone package. 16 | 17 | 18 | Please see https://github.com/MRCollective/NHibernate.SqlAzure/releases for release notes and https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/BREAKING_CHANGES.md for any breaking changes. 19 | 20 | 21 | https://github.com/MRCollective/NHibernate.SqlAzure 22 | 23 | 24 | https://github.com/MRCollective/NHibernate.SqlAzure/blob/master/LICENSE 25 | 26 | 27 | https://raw.github.com/MRCollective/NHibernate.SqlAzure/master/logo.png 28 | 29 | 30 | nhibernate, azure, sql, sql azure, transient 31 | 32 | 33 | en-US 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NHibernate5.SqlAzure")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NHibernate5.SqlAzure")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("895b6f59-b5be-4796-847d-c3ff2c7eed66")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/ReliableAdoNetWithDistributedTransactionFactory.cs: -------------------------------------------------------------------------------- 1 | using NHibernate.Engine; 2 | using NHibernate.Engine.Transaction; 3 | using NHibernate.Transaction; 4 | 5 | namespace NHibernate.SqlAzure 6 | { 7 | /// 8 | /// An NHibernate transaction factory that provides retry logic for transient errors when executing transactions. 9 | /// It is aware of Distributed Transactions. 10 | /// 11 | /// 12 | /// Requires the connection to be a 13 | /// 14 | public class ReliableAdoNetWithDistributedTransactionFactory : AdoNetWithSystemTransactionFactory, ITransactionFactory 15 | { 16 | public new ITransaction CreateTransaction(ISessionImplementor session) 17 | { 18 | return new ReliableAdoTransaction(session); 19 | } 20 | 21 | /// 22 | /// Executes some work in isolation. 23 | /// 24 | /// The NHibernate session 25 | /// The work to execute 26 | /// Whether or not to wrap the work in a transaction 27 | public new void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, bool transacted) 28 | { 29 | var connection = (ReliableSqlDbConnection) session.Connection; 30 | 31 | ReliableAdoTransaction.ExecuteWithRetry(connection, 32 | () => base.ExecuteWorkInIsolation(session, work, transacted) 33 | ); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/ReliableSql2008ClientDriver.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; 3 | using NHibernate.AdoNet; 4 | using NHibernate.Driver; 5 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 6 | 7 | namespace NHibernate.SqlAzure 8 | { 9 | using System.Data.Common; 10 | 11 | /// 12 | /// Abstract base class that enables the creation of an NHibernate client driver that extends the Sql 2008 driver, 13 | /// but adds in transient fault handling retry logic via . 14 | /// 15 | public abstract class ReliableSql2008ClientDriver : Sql2008ClientDriver, IEmbeddedBatcherFactoryProvider 16 | { 17 | /// 18 | /// Provides a instance to use for connections. 19 | /// 20 | /// A reliable connection 21 | protected abstract ReliableSqlConnection CreateReliableConnection(); 22 | 23 | /// 24 | /// Creates an uninitialized object for the SqlClientDriver. 25 | /// 26 | /// 27 | /// An unitialized object. 28 | /// 29 | public override DbConnection CreateConnection() 30 | { 31 | return new ReliableSqlDbConnection(CreateReliableConnection()); 32 | } 33 | 34 | /// 35 | /// Creates an uninitialized object for the SqlClientDriver. 36 | /// 37 | /// 38 | /// An unitialized object. 39 | /// 40 | public override DbCommand CreateCommand() 41 | { 42 | return new ReliableSqlCommand(); 43 | } 44 | 45 | /// 46 | /// Returns the class to use for the Batcher Factory. 47 | /// 48 | public System.Type BatcherFactoryClass 49 | { 50 | get { return typeof(ReliableSqlClientBatchingBatcherFactory); } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/ReliableSqlClientBatchingBatcher.cs: -------------------------------------------------------------------------------- 1 | // Parts of this file were copied from NHibernate.AdoNet.SqlClientBatchingBatcherFactory, but modified to use ReliableSqlDbConnection 2 | // The #regions indicate the copied code 3 | using System; 4 | using System.Data; 5 | using System.Data.Common; 6 | using System.Reflection; 7 | using System.Text; 8 | using NHibernate.AdoNet; 9 | using NHibernate.AdoNet.Util; 10 | using NHibernate.Exceptions; 11 | 12 | namespace NHibernate.SqlAzure 13 | { 14 | /// 15 | /// Exposes functionality when a 16 | /// connection is being used. 17 | /// 18 | public class ReliableSqlClientBatchingBatcher : SqlClientBatchingBatcher 19 | { 20 | #region Impersonate private fields in base class 21 | private readonly ConnectionManager _connectionManager; 22 | private readonly FieldInfo _totalExpectedRowsAffectedField = typeof(SqlClientBatchingBatcher) 23 | .GetField("_totalExpectedRowsAffected", BindingFlags.NonPublic | BindingFlags.Instance); 24 | private readonly FieldInfo _currentBatchField = typeof (SqlClientBatchingBatcher) 25 | .GetField("_currentBatch", BindingFlags.NonPublic | BindingFlags.Instance); 26 | private readonly FieldInfo _currentBatchCommandsLogField = typeof(SqlClientBatchingBatcher) 27 | .GetField("_currentBatchCommandsLog", BindingFlags.NonPublic | BindingFlags.Instance); 28 | private readonly MethodInfo _createConfiguredBatchMethod = typeof (SqlClientBatchingBatcher) 29 | .GetMethod("CreateConfiguredBatch", BindingFlags.Instance | BindingFlags.NonPublic); 30 | 31 | // ReSharper disable InconsistentNaming 32 | private int _totalExpectedRowsAffected 33 | { 34 | get { return (int)_totalExpectedRowsAffectedField.GetValue(this); } 35 | set { _totalExpectedRowsAffectedField.SetValue(this, value); } 36 | } 37 | private SqlClientSqlCommandSet _currentBatch 38 | { 39 | get { return (SqlClientSqlCommandSet)_currentBatchField.GetValue(this); } 40 | set { _currentBatchField.SetValue(this, value); } 41 | } 42 | private StringBuilder _currentBatchCommandsLog 43 | { 44 | get { return (StringBuilder) _currentBatchCommandsLogField.GetValue(this); } 45 | set { _currentBatchCommandsLogField.SetValue(this, value); } 46 | } 47 | private int _batchSize 48 | { 49 | get { return BatchSize; } 50 | } 51 | // ReSharper restore InconsistentNaming 52 | 53 | private SqlClientSqlCommandSet CreateConfiguredBatch() 54 | { 55 | return (SqlClientSqlCommandSet)_createConfiguredBatchMethod.Invoke(this, null); 56 | } 57 | 58 | public ReliableSqlClientBatchingBatcher(ConnectionManager connectionManager, IInterceptor interceptor) 59 | : base(connectionManager, interceptor) 60 | { 61 | _connectionManager = connectionManager; 62 | } 63 | #endregion 64 | 65 | public override void AddToBatch(IExpectation expectation) 66 | { 67 | #region NHibernate code 68 | _totalExpectedRowsAffected += expectation.ExpectedRowCount; 69 | DbCommand batchUpdate = CurrentCommand; 70 | Driver.AdjustCommand(batchUpdate); 71 | string lineWithParameters = null; 72 | var sqlStatementLogger = Factory.Settings.SqlStatementLogger; 73 | if (sqlStatementLogger.IsDebugEnabled || Log.IsDebugEnabled()) 74 | { 75 | lineWithParameters = sqlStatementLogger.GetCommandLineWithParameters(batchUpdate); 76 | var formatStyle = sqlStatementLogger.DetermineActualStyle(FormatStyle.Basic); 77 | lineWithParameters = formatStyle.Formatter.Format(lineWithParameters); 78 | _currentBatchCommandsLog.Append("command ") 79 | .Append(_currentBatch.CountOfCommands) 80 | .Append(":") 81 | .AppendLine(lineWithParameters); 82 | } 83 | if (Log.IsDebugEnabled()) 84 | { 85 | Log.Debug("Adding to batch:" + lineWithParameters); 86 | } 87 | #endregion 88 | _currentBatch.Append((System.Data.SqlClient.SqlCommand)(ReliableSqlCommand)batchUpdate); 89 | #region NHibernate code 90 | if (_currentBatch.CountOfCommands >= _batchSize) 91 | { 92 | ExecuteBatchWithTiming(batchUpdate); 93 | } 94 | #endregion 95 | } 96 | 97 | // Need this method call in this class rather than the base class to ensure Prepare is called... if only it was virtual :( 98 | protected void ExecuteBatch(IDbCommand ps) 99 | { 100 | #region NHibernate code 101 | Log.Debug("Executing batch"); 102 | CheckReaders(); 103 | Prepare(_currentBatch.BatchCommand); 104 | if (Factory.Settings.SqlStatementLogger.IsDebugEnabled) 105 | { 106 | Factory.Settings.SqlStatementLogger.LogBatchCommand(_currentBatchCommandsLog.ToString()); 107 | _currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:"); 108 | } 109 | 110 | int rowsAffected; 111 | try 112 | { 113 | rowsAffected = _currentBatch.ExecuteNonQuery(); 114 | } 115 | catch (DbException e) 116 | { 117 | throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not execute batch command."); 118 | } 119 | 120 | Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, rowsAffected); 121 | 122 | _currentBatch.Dispose(); 123 | _totalExpectedRowsAffected = 0; 124 | _currentBatch = CreateConfiguredBatch(); 125 | #endregion 126 | } 127 | 128 | /// 129 | /// Prepares the for execution in the database. 130 | /// 131 | /// 132 | /// This takes care of hooking the up to an 133 | /// and if one exists. It will call Prepare if the Driver 134 | /// supports preparing commands. 135 | /// 136 | protected new void Prepare(DbCommand cmd) 137 | { 138 | try 139 | { 140 | var sessionConnection = (ReliableSqlDbConnection)_connectionManager.GetConnection(); 141 | 142 | #region NHibernate code 143 | if (cmd.Connection != null) 144 | { 145 | // make sure the commands connection is the same as the Sessions connection 146 | // these can be different when the session is disconnected and then reconnected 147 | if (cmd.Connection != sessionConnection) 148 | { 149 | cmd.Connection = (System.Data.SqlClient.SqlConnection) sessionConnection; 150 | } 151 | } 152 | else 153 | { 154 | cmd.Connection = (System.Data.SqlClient.SqlConnection) sessionConnection; 155 | } 156 | 157 | _connectionManager.Transaction.Enlist(cmd); 158 | Driver.PrepareCommand(cmd); 159 | #endregion 160 | } 161 | catch (InvalidOperationException ioe) 162 | { 163 | #region NHibernate code 164 | throw new ADOException("While preparing " + cmd.CommandText + " an error occurred", ioe); 165 | #endregion 166 | } 167 | } 168 | 169 | protected override void DoExecuteBatch(DbCommand ps) 170 | { 171 | var connection = (ReliableSqlDbConnection)_connectionManager.GetConnection(); 172 | ReliableAdoTransaction.ExecuteWithRetry(connection, () => ExecuteBatch(ps)); 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/ReliableSqlCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; 4 | using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling; 5 | 6 | namespace NHibernate.SqlAzure 7 | { 8 | using System.Data.Common; 9 | 10 | /// 11 | /// An implementation that wraps a object such that any 12 | /// queries that are executed are executed via a . 13 | /// 14 | /// 15 | /// Note: For this to work it requires that the Connection property be set with a object. 16 | /// 17 | public class ReliableSqlCommand : DbCommand 18 | { 19 | /// 20 | /// The underlying being proxied. 21 | /// 22 | public System.Data.SqlClient.SqlCommand Current { get; private set; } 23 | 24 | /// 25 | /// The that has been assigned to the command via the Connection property. 26 | /// 27 | public ReliableSqlConnection ReliableConnection { get; set; } 28 | 29 | /// 30 | /// Constructs a . 31 | /// 32 | public ReliableSqlCommand() 33 | { 34 | Current = new System.Data.SqlClient.SqlCommand(); 35 | } 36 | 37 | /// 38 | /// Explicit type-casting between a and a . 39 | /// 40 | /// The being casted 41 | /// The underlying being proxied. 42 | public static explicit operator System.Data.SqlClient.SqlCommand(ReliableSqlCommand command) 43 | { 44 | return command.Current; 45 | } 46 | 47 | /// 48 | /// Returns the underlying and expects a when being set. 49 | /// 50 | protected override DbConnection DbConnection 51 | { 52 | get { return Current.Connection; } 53 | set 54 | { 55 | ReliableConnection = ((ReliableSqlDbConnection)value).ReliableConnection; 56 | Current.Connection = ReliableConnection.Current; 57 | } 58 | } 59 | 60 | 61 | #region Wrapping code 62 | 63 | 64 | public override void Prepare() 65 | { 66 | Current.Prepare(); 67 | } 68 | 69 | public override void Cancel() 70 | { 71 | Current.Cancel(); 72 | } 73 | 74 | protected override DbParameter CreateDbParameter() 75 | { 76 | return Current.CreateParameter(); 77 | } 78 | 79 | public override int ExecuteNonQuery() 80 | { 81 | return ReliableConnection.ExecuteCommand(Current); 82 | } 83 | 84 | public IDataReader ExecuteReader() 85 | { 86 | return ReliableConnection.ExecuteCommand(Current); 87 | } 88 | 89 | protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) 90 | { 91 | return ReliableConnection.ExecuteCommand(Current, behavior); 92 | } 93 | 94 | public override object ExecuteScalar() 95 | { 96 | return ReliableConnection.ExecuteCommand(Current); 97 | } 98 | 99 | protected override DbTransaction DbTransaction 100 | { 101 | get { return Current.Transaction; } 102 | set { Current.Transaction = (SqlTransaction)value; } 103 | } 104 | 105 | public override bool DesignTimeVisible 106 | { 107 | get { return Current.DesignTimeVisible; } 108 | set { Current.DesignTimeVisible = value; } 109 | } 110 | 111 | public override string CommandText 112 | { 113 | get { return Current.CommandText; } 114 | set { Current.CommandText = value; } 115 | } 116 | 117 | public override int CommandTimeout 118 | { 119 | get { return Current.CommandTimeout; } 120 | set { Current.CommandTimeout = value; } 121 | } 122 | 123 | public override CommandType CommandType 124 | { 125 | get { return Current.CommandType; } 126 | set { Current.CommandType = value; } 127 | } 128 | 129 | protected override DbParameterCollection DbParameterCollection 130 | { 131 | get { return Current.Parameters; } 132 | } 133 | 134 | public override UpdateRowSource UpdatedRowSource 135 | { 136 | get { return Current.UpdatedRowSource; } 137 | set { Current.UpdatedRowSource = value; } 138 | } 139 | #endregion 140 | } 141 | } -------------------------------------------------------------------------------- /NHibernate5.SqlAzure/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /PreBuild.ps1: -------------------------------------------------------------------------------- 1 | 2 | [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null 3 | [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null 4 | 5 | $serverName = $env:COMPUTERNAME 6 | $instanceName = 'SQL2019' 7 | 8 | $smo = 'Microsoft.SqlServer.Management.Smo.' 9 | $wmi = new-object ($smo + 'Wmi.ManagedComputer') 10 | 11 | # Enable TCP/IP 12 | $uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']" 13 | $Tcp = $wmi.GetSmoObject($uri) 14 | $Tcp.IsEnabled = $true 15 | $TCP.alter() 16 | 17 | # Enable named pipes 18 | $uri = "ManagedComputer[@Name='$serverName']/ ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Np']" 19 | $Np = $wmi.GetSmoObject($uri) 20 | $Np.IsEnabled = $true 21 | $Np.Alter() 22 | 23 | Set-Service SQLBrowser -StartupType Manual 24 | Start-Service SQLBrowser 25 | Start-Service "MSSQL`$$instanceName" 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NHibernate Reliable SQL Azure Driver 2 | ==================================== 3 | 4 | [![Build status](https://ci.appveyor.com/api/projects/status/8wn6khaxpo16frgy?svg=true)](https://ci.appveyor.com/project/MRCollective/nhibernate-sqlazure) 5 | [![NuGet downloads](https://img.shields.io/nuget/dt/NHibernate.SQLAzure.svg)](https://www.nuget.org/packages/NHibernate.SQLAzure) 6 | [![NuGet version](https://img.shields.io/nuget/vpre/NHibernate.SQLAzure.svg)](https://www.nuget.org/packages/NHibernate.SQLAzure) 7 | 8 | Provides an NHibernate driver that uses the Microsoft Transient Fault Handling library to allow for reliable SQL Azure connections. 9 | 10 | This library is build against version 3.3.1.4000 of NHibernate so you will need to update to that version or later to use this library. 11 | 12 | Version 2 of this library targets the new version (6) of the Enterprise Library code and as such requires .NET 4.5. If you have a .NET 4.0 application then feel free to use the [latest version in the 1.0 range of this library](https://www.nuget.org/packages/NHibernate.SqlAzure/1.0.0.37). 13 | 14 | Using the provider when using Fluent NHibernate 15 | ----------------------------------------------- 16 | 17 | To use the provider: 18 | 19 | 1. `Update-Package FluentNHibernate` 20 | 2. `Install-Package NHibernate.SqlAzure` 21 | * or if you want the version that isn't IL-merged with the Microsoft Transient Fault Handling library then `Install-Package NHibernate.SqlAzure.Standalone` (note: that will add 2 other dependencies as well) 22 | 3. Set the `Database` to use `SqlAzureClientDriver` as the client driver (note: if you get Timeout exceptions then see the Advanced section below), e.g.: 23 | 24 | Fluently.Configure() 25 | .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString).Driver()) 26 | 27 | Using the provider when using an XML configuration 28 | -------------------------------------------------- 29 | 30 | To use the provider: 31 | 32 | 1. `Update-Package NHibernate` 33 | 2. `Install-Package NHibernate.SqlAzure` 34 | * or if you want the version that isn't IL-merged with the Microsoft Transient Fault Handling library then `Install-Package NHibernate.SqlAzure.Standalone` (note: that will add 2 other dependencies as well) 35 | 3. Set the `connection.driver_class` property on the session factory configuration to `NHibernate.SqlAzure.SqlAzureClientDriver, NHibernate.SqlAzure` (note: if you get Timeout exceptions then see the Advanced section below). 36 | 37 | NHibernate 4 support 38 | -------------------- 39 | 40 | We have NHibernate 4 supports via separate NuGet packages thanks to [@rytmis](https://github.com/rytmis): 41 | 42 | * `Install-Package NHibernate4.SqlAzure` 43 | * `Install-Package NHibernate4.SqlAzure.Standalone` 44 | 45 | Reliable transactions 46 | --------------------- 47 | 48 | The Enterprise Library code doesn't seem to provide any rety logic when beginning transactions. This may be because it will rarely be a problem or you might not want to continue the transaction if there was a potential problem starting it. However, in order to get the unit tests for this library to pass, I needed the transaction to be resilient too so I created some classes that allow you to add retry logic when beginning a transaction. This may well be useful to others so we've included it as part of the library. See the next two sections to understand how to make use of this. 49 | 50 | Using reliable transactions when using Fluent NHibernate 51 | -------------------------------------------------------- 52 | 53 | Set the `TransactionStrategy` environment property to use the `ReliableAdoNetWithDistributedTransactionFactory` class: 54 | 55 | config.ExposeConfiguration(c => c.SetProperty(Environment.TransactionStrategy, 56 | typeof(ReliableAdoNetWithDistributedTransactionFactory).AssemblyQualifiedName)); 57 | 58 | Using reliable transactions when using an XML configuration 59 | ----------------------------------------------------------- 60 | 61 | Set the `transaction.factory_class` property on the session factory configuration to `NHibernate.SqlAzure.ReliableAdoNetWithDistributedTransactionFactory, NHibernate.SqlAzure`. 62 | 63 | Advanced Usage: Extending the provider, add logging for failed attempts or apply different retry strategies / transient error detection strategies 64 | ---------------------------------------------------------------------------------------------------------------------------------- 65 | 66 | It's possible for Timeout exceptions to be both a [transient error caused by Azure and a legitimate timeout caused by unoptimised queries](http://social.msdn.microsoft.com/Forums/en-US/ssdsgetstarted/thread/7a50985d-92c2-472f-9464-a6591efec4b3/) so we've included a transient error detection strategy that detects these timeout exceptions as a transient error and retries. To use it simply change your driver from `SqlAzureClientDriver` to `SqlAzureClientDriverWithTimeoutRetries`. There are a few things to note: 67 | 68 | * We recommend you try the `SqlAzureClientDriver` first and then add the one that detects timeouts as transient errors only after you experience timeout errors that you are sure are caused by SQL Azure and not your code 69 | * If the timeout happened in the first place it means that the user's request has already taken a long time so applying a retry policy to that query will make it take even longer (and if the retries also timeout then the page request might even time out (for a web application)). 70 | * If you want visibility of retries then see below for the instructions about how to log retries 71 | 72 | There are two abstract base driver classes that you can extend to get more control over the retry policies and use to hook in logging of retries: 73 | 74 | * `ReliableSql2008ClientDriver`: Takes care of wrapping the internals of NHibernate to use a `ReliableSqlConnection` rather than a `SqlConnection`. You simply need to override the `CreateReliableConnection` method and instantiate your own `ReliableSqlConnection` in any way you like 75 | * `DefaultReliableSql2008ClientDriver`: 76 | * Defines a connection and command retry policy (based on the example ones used in the [Transient Fault Handling documentation](http://msdn.microsoft.com/en-us/library/hh680900.aspx) 77 | * Includes overridable methods to return event handlers for logging when any retries occur (`RetryEventHandler`) or alternatively logging when a specific type of retry occurs (`CommandRetryEventHandler` and `ConnectionRetryEventHandler`) 78 | * Allows you to define what transient error detection strategy you want to use (`TTransientErrorDetectionStrategy`); there are two included in this library that you can use and / or extend (and of course you can always create a completely custom one by extending `ITransientErrorDetectionStrategy`; for an example check out `NHibernate.SqlAzure.Tests.Config.SqlExpressTransientErrorDetectionStrategy` in the test project of the source code): 79 | * `NHibernate.SqlAzure.RetryStrategies.SqlAzureTransientErrorDetectionStrategy`: A clone of the error detection strategy that comes with the Transient Faut Handling library (except it's not sealed and the `IsTransient` method is virtual so you can extend it 80 | * `NHibernate.SqlAzure.RetryStrategies.SqlAzureTransientErrorDetectionStrategyWithTimeouts`: The same as above with the addition of detecting timeout exceptions as a transient error; use this with caution as per above 81 | 82 | Running the tests 83 | ----------------- 84 | 85 | If you want to contribute to this library then you need to: 86 | 87 | 1. Load the solution (allow the NuGet package restore to grab all the packages) 88 | 2. Compile the solution (.NET 4, AnyCPU) 89 | 3. Create a database on your local SQLExpress instance called `NHibernateSqlAzureTests` and grant the user running the NUnit runner `dbowner` access. 90 | * If you want to use a different database simply change the `Database` ConnectionString in `App.config` as well as the `SqlServerServiceName` AppSetting if necessary. 91 | 4. Run the `NHibernate.SqlAzure.Tests` project with your NUnit test runner of choice 92 | * The user running the tests must have Administrator access on the computer so that the Windows Service for the database can be shutdown and restarted 93 | * Note: Your database will be taken down and brought back up repeatedly when running the tests so only run them against a development database. 94 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MRCollective/NHibernate.SqlAzure/3e5615484df2f8abad5d803c91011a4c052d3563/logo.png -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------