diff --git a/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs b/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs index 327b32faddd..8ba7864c882 100644 --- a/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs +++ b/src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using System.Data.SqlClient; using System.IO; @@ -11,12 +12,26 @@ using NHibernate.Hql.Ast.ANTLR; using NHibernate.Type; using NUnit.Framework; +using Environment = NHibernate.Cfg.Environment; namespace NHibernate.Test.CfgTest.Loquacious { [TestFixture] public class ConfigurationFixture { + [Test] + public void CanSetNotificationHandler() + { + //NH-3724 + EventHandler handler = (s, e) => {}; + var cfg = new Configuration().DataBaseIntegration(x => + { + x.WithNotificationHandler(handler); + }).Configure(); + + Assert.IsNotNull(cfg.NotificationHandler); + } + [Test] public void CompleteConfiguration() { diff --git a/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs index 22267fb030c..bf2431d5f3e 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs @@ -179,6 +179,11 @@ void IDriver.Configure(IDictionary settings) _driverImplementation.Configure(settings); } + public void AddNotificationHandler(DbConnection con, Delegate handler) + { + _driverImplementation.AddNotificationHandler(con, handler); + } + DbConnection IDriver.CreateConnection() { return _driverImplementation.CreateConnection(); diff --git a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs index 67b36a0d2cc..61559329d39 100644 --- a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs @@ -630,6 +630,11 @@ void IDriver.Configure(IDictionary settings) _driverImplementation.Configure(settings); } + public void AddNotificationHandler(DbConnection con, Delegate handler) + { + _driverImplementation.AddNotificationHandler(con, handler); + } + DbConnection IDriver.CreateConnection() { return _driverImplementation.CreateConnection(); diff --git a/src/NHibernate/AdoNet/ConnectionManager.cs b/src/NHibernate/AdoNet/ConnectionManager.cs index 80674df3cf5..0d27d81d4ee 100644 --- a/src/NHibernate/AdoNet/ConnectionManager.cs +++ b/src/NHibernate/AdoNet/ConnectionManager.cs @@ -240,6 +240,11 @@ public DbConnection GetConnection() if (_ownConnection) { _connection = Factory.ConnectionProvider.GetConnection(); + //NH-3724 + if (Factory.Settings.NotificationHandler != null) + { + Factory.ConnectionProvider.Driver.AddNotificationHandler(_connection, Factory.Settings.NotificationHandler); + } // Will fail if the connection is already enlisted in another transaction. // Probable case: nested transaction scope with connection auto-enlistment enabled. // That is an user error. diff --git a/src/NHibernate/Async/AdoNet/ConnectionManager.cs b/src/NHibernate/Async/AdoNet/ConnectionManager.cs index a7a942d8735..ce8db4cc505 100644 --- a/src/NHibernate/Async/AdoNet/ConnectionManager.cs +++ b/src/NHibernate/Async/AdoNet/ConnectionManager.cs @@ -62,6 +62,11 @@ async Task InternalGetConnectionAsync() if (_ownConnection) { _connection = await (Factory.ConnectionProvider.GetConnectionAsync(cancellationToken)).ConfigureAwait(false); + //NH-3724 + if (Factory.Settings.NotificationHandler != null) + { + Factory.ConnectionProvider.Driver.AddNotificationHandler(_connection, Factory.Settings.NotificationHandler); + } // Will fail if the connection is already enlisted in another transaction. // Probable case: nested transaction scope with connection auto-enlistment enabled. // That is an user error. diff --git a/src/NHibernate/Cfg/Configuration.cs b/src/NHibernate/Cfg/Configuration.cs index cf6a0623c42..126a2a0a826 100644 --- a/src/NHibernate/Cfg/Configuration.cs +++ b/src/NHibernate/Cfg/Configuration.cs @@ -183,6 +183,7 @@ protected void Reset() tableNameBinding = new Dictionary(); columnNameBindingPerTable = new Dictionary(); filtersSecondPasses = new Queue(); + NotificationHandler = null; } [Serializable] @@ -1405,6 +1406,14 @@ public Configuration SetDefaultNamespace(string newDefaultNamespace) return this; } + //NH-3724 + + public Delegate NotificationHandler + { + get => _notificationHandler; + set => _notificationHandler = value; + } + /// /// Sets the default interceptor for use by all sessions. /// @@ -1763,6 +1772,8 @@ private Settings BuildSettings() // NH : Set configuration for IdGenerator SQL logging PersistentIdGeneratorParmsNames.SqlStatementLogger.FormatSql = result.SqlStatementLogger.FormatSql; PersistentIdGeneratorParmsNames.SqlStatementLogger.LogToStdout = result.SqlStatementLogger.LogToStdout; + //NH-3724 + result.NotificationHandler = NotificationHandler; return result; } @@ -1928,6 +1939,9 @@ protected virtual string GetDefaultConfigurationFilePath() #endregion private XmlSchemas schemas; + + [NonSerialized] + private Delegate _notificationHandler; private XmlSchemas Schemas { diff --git a/src/NHibernate/Cfg/Loquacious/DbIntegrationConfigurationProperties.cs b/src/NHibernate/Cfg/Loquacious/DbIntegrationConfigurationProperties.cs index 55131818ab4..176c98557b2 100644 --- a/src/NHibernate/Cfg/Loquacious/DbIntegrationConfigurationProperties.cs +++ b/src/NHibernate/Cfg/Loquacious/DbIntegrationConfigurationProperties.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using NHibernate.AdoNet; using NHibernate.Connection; @@ -19,6 +20,12 @@ public DbIntegrationConfigurationProperties(Configuration configuration) #region Implementation of IDbIntegrationConfigurationProperties + public void WithNotificationHandler(Delegate handler) + { + //NH-3724 + configuration.NotificationHandler = handler; + } + public void Dialect() where TDialect : Dialect.Dialect { configuration.SetProperty(Environment.Dialect, typeof(TDialect).AssemblyQualifiedName); diff --git a/src/NHibernate/Cfg/Loquacious/IDbIntegrationConfigurationProperties.cs b/src/NHibernate/Cfg/Loquacious/IDbIntegrationConfigurationProperties.cs index 496ebf58433..97e53751d45 100644 --- a/src/NHibernate/Cfg/Loquacious/IDbIntegrationConfigurationProperties.cs +++ b/src/NHibernate/Cfg/Loquacious/IDbIntegrationConfigurationProperties.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using NHibernate.AdoNet; using NHibernate.Connection; @@ -15,6 +16,9 @@ public interface IDbIntegrationConfigurationProperties bool LogSqlInConsole { set; } bool LogFormattedSql { set; } + //NH-3724 + void WithNotificationHandler(Delegate handler); + void ConnectionProvider() where TProvider : IConnectionProvider; void Driver() where TDriver : IDriver; IsolationLevel IsolationLevel { set; } diff --git a/src/NHibernate/Cfg/Settings.cs b/src/NHibernate/Cfg/Settings.cs index 878b9b60605..c7172b82010 100644 --- a/src/NHibernate/Cfg/Settings.cs +++ b/src/NHibernate/Cfg/Settings.cs @@ -31,6 +31,9 @@ public Settings() //private int jdbcFetchSize; #endregion + + public Delegate NotificationHandler { get; internal set; } + public SqlStatementLogger SqlStatementLogger { get; internal set; } public int MaximumFetchDepth { get; internal set; } diff --git a/src/NHibernate/Driver/DriverBase.cs b/src/NHibernate/Driver/DriverBase.cs index 1d63bc64dd8..fea21fbd627 100644 --- a/src/NHibernate/Driver/DriverBase.cs +++ b/src/NHibernate/Driver/DriverBase.cs @@ -21,6 +21,22 @@ public abstract class DriverBase : IDriver, ISqlParameterFormatter private int commandTimeout; private bool prepareSql; + public virtual void AddNotificationHandler(DbConnection con, Delegate handler) + { + //NH-3724 + if (handler != null) + { + var prop = con.GetType().GetEvent("InfoMessage"); + + if (prop == null) + { + throw new NotSupportedException("Current driver does not support notifications."); + } + + prop.AddEventHandler(con, handler); + } + } + public virtual void Configure(IDictionary settings) { // Command timeout diff --git a/src/NHibernate/Driver/IDriver.cs b/src/NHibernate/Driver/IDriver.cs index 61e40b64213..38c9f3cc978 100644 --- a/src/NHibernate/Driver/IDriver.cs +++ b/src/NHibernate/Driver/IDriver.cs @@ -37,6 +37,14 @@ public interface IDriver /// void Configure(IDictionary settings); + //NH-3724 + /// + /// Attaches an event handler for the notification event (InfoMessage in most ADO.NET drivers). + /// + /// + /// + void AddNotificationHandler(DbConnection con, Delegate handler); + /// /// Creates an uninitialized DbConnection object for the specific Driver /// diff --git a/src/NHibernate/Driver/IfxDriver.cs b/src/NHibernate/Driver/IfxDriver.cs index 0d3c3bebbd2..32a18f1d7c3 100644 --- a/src/NHibernate/Driver/IfxDriver.cs +++ b/src/NHibernate/Driver/IfxDriver.cs @@ -1,3 +1,6 @@ +using System; +using System.Data; + namespace NHibernate.Driver { /// diff --git a/src/NHibernate/Driver/NpgsqlDriver.cs b/src/NHibernate/Driver/NpgsqlDriver.cs index ccfd2dc1be2..0f19e27e6ce 100644 --- a/src/NHibernate/Driver/NpgsqlDriver.cs +++ b/src/NHibernate/Driver/NpgsqlDriver.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using System.Data.Common; using NHibernate.AdoNet; @@ -41,6 +42,12 @@ public NpgsqlDriver() : base( { } + public override void AddNotificationHandler(DbConnection con, Delegate handler) + { + //NH-3724 + con.GetType().GetEvent("Notification").AddEventHandler(con, handler); + } + public override bool UseNamedPrefixInSql => true; public override bool UseNamedPrefixInParameter => true; diff --git a/src/NHibernate/Driver/OdbcDriver.cs b/src/NHibernate/Driver/OdbcDriver.cs index 80e6358617e..68dc15cf887 100644 --- a/src/NHibernate/Driver/OdbcDriver.cs +++ b/src/NHibernate/Driver/OdbcDriver.cs @@ -38,6 +38,7 @@ public override void Configure(IDictionary settings) } } + #if !NETFX public OdbcDriver() : base("System.Data.Odbc", "System.Data.Odbc.OdbcConnection", "System.Data.Odbc.OdbcCommand") @@ -49,6 +50,12 @@ public override DbConnection CreateConnection() return new System.Data.Odbc.OdbcConnection(); } + public override void AddNotificationHandler(DbConnection con, Delegate handler) + { + //NH-3724 + (con as System.Data.Odbc.OdbcConnection).InfoMessage += (System.Data.Odbc.OdbcInfoMessageEventHandler) handler; + } + public override DbCommand CreateCommand() { return new System.Data.Odbc.OdbcCommand(); diff --git a/src/NHibernate/Driver/OleDbDriver.cs b/src/NHibernate/Driver/OleDbDriver.cs index 504411995e0..e2cab75baa9 100644 --- a/src/NHibernate/Driver/OleDbDriver.cs +++ b/src/NHibernate/Driver/OleDbDriver.cs @@ -28,6 +28,12 @@ public override DbConnection CreateConnection() return new System.Data.OleDb.OleDbConnection(); } + public override void AddNotificationHandler(DbConnection con, Delegate handler) + { + //NH-3724 + (con as System.Data.OleDb.OleDbConnection).InfoMessage += (System.Data.OleDb.OleDbInfoMessageEventHandler) handler; + } + public override DbCommand CreateCommand() { return new System.Data.OleDb.OleDbCommand(); diff --git a/src/NHibernate/Driver/SqlClientDriver.cs b/src/NHibernate/Driver/SqlClientDriver.cs index 81d46097a50..a65bce1ae18 100644 --- a/src/NHibernate/Driver/SqlClientDriver.cs +++ b/src/NHibernate/Driver/SqlClientDriver.cs @@ -9,7 +9,6 @@ using NHibernate.Dialect; using NHibernate.Engine; using NHibernate.SqlTypes; -using NHibernate.Type; namespace NHibernate.Driver { @@ -88,6 +87,12 @@ public override DbConnection CreateConnection() return new SqlConnection(); } + public override void AddNotificationHandler(DbConnection con, Delegate handler) + { + //NH-3724 + (con as SqlConnection).InfoMessage += (SqlInfoMessageEventHandler) handler; + } + /// /// Creates an uninitialized object for /// the SqlClientDriver.