From 03b7d06a143c3a754bb18276740a487c07f762bd Mon Sep 17 00:00:00 2001 From: root Date: Mon, 23 Feb 2026 21:31:07 +0100 Subject: [PATCH] Harden disposal paths and test project metadata --- DynamORM.Tests/DynamORM.Tests.csproj | 17 ++--- .../Implementation/DynamicQueryBuilder.cs | 21 +++--- DynamORM/DynamicCachedReader.cs | 47 +++++++++---- DynamORM/DynamicCommand.cs | 68 ++++++++++++------- DynamORM/DynamicConnection.cs | 24 ++++--- DynamORM/DynamicDatabase.cs | 33 +++++---- DynamORM/DynamicProcedureInvoker.cs | 29 +++++--- DynamORM/DynamicTable.cs | 23 ++++--- DynamORM/DynamicTransaction.cs | 29 +++++--- DynamORM/Helpers/Dynamics/DynamicParser.cs | 23 ++++--- 10 files changed, 192 insertions(+), 122 deletions(-) diff --git a/DynamORM.Tests/DynamORM.Tests.csproj b/DynamORM.Tests/DynamORM.Tests.csproj index fd25143..b197d61 100644 --- a/DynamORM.Tests/DynamORM.Tests.csproj +++ b/DynamORM.Tests/DynamORM.Tests.csproj @@ -1,8 +1,8 @@  - - net8.0 - Dynamic Object-Relational Mapping tests library. + + net8.0 + Dynamic Object-Relational Mapping tests library. Copyright © RUSSEK Software 2012-2026 RUSSEK Software Grzegorz Russek @@ -11,10 +11,11 @@ https://dr4cul4.pl DynamORM MIT - Library - false - enable - + Library + false + true + enable + @@ -41,4 +42,4 @@ - \ No newline at end of file + diff --git a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs index 7b9ebda..e14ad7c 100644 --- a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs @@ -960,14 +960,17 @@ namespace DynamORM.Builders.Implementation /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - public virtual void Dispose() - { - IsDisposed = true; - - if (Database != null) - Database.RemoveFromCache(this); + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + public virtual void Dispose() + { + if (IsDisposed) + return; + + IsDisposed = true; + + if (Database != null) + Database.RemoveFromCache(this); if (Parameters != null) { @@ -994,4 +997,4 @@ namespace DynamORM.Builders.Implementation #endregion IExtendedDisposable } -} \ No newline at end of file +} diff --git a/DynamORM/DynamicCachedReader.cs b/DynamORM/DynamicCachedReader.cs index cd40559..d40e416 100644 --- a/DynamORM/DynamicCachedReader.cs +++ b/DynamORM/DynamicCachedReader.cs @@ -30,8 +30,9 @@ namespace DynamORM internal IList _cache; } - private List _data = new List(); - private int _currentDataPosition = 0; + private List _data = new List(); + private int _currentDataPosition = 0; + private bool _isDisposed; private DynamicCachedReader() { @@ -443,18 +444,34 @@ namespace DynamORM /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. - public void Dispose() - { - foreach (var data in _data) - { - data._names.Clear(); - data._types.Clear(); - data._cache.Clear(); - data._schema.Dispose(); - } - - _data.Clear(); - } + public void Dispose() + { + if (_isDisposed) + return; + + _isDisposed = true; + IsClosed = true; + + if (_data == null) + return; + + foreach (var data in _data) + { + if (data == null) + continue; + + if (data._names != null) + data._names.Clear(); + if (data._types != null) + data._types.Clear(); + if (data._cache != null) + data._cache.Clear(); + if (data._schema != null) + data._schema.Dispose(); + } + + _data.Clear(); + } #endregion IDisposable Members @@ -721,4 +738,4 @@ namespace DynamORM #endregion IDataRecord Members } -} \ No newline at end of file +} diff --git a/DynamORM/DynamicCommand.cs b/DynamORM/DynamicCommand.cs index 6ae0c68..657b37e 100644 --- a/DynamORM/DynamicCommand.cs +++ b/DynamORM/DynamicCommand.cs @@ -260,35 +260,51 @@ namespace DynamORM #region IExtendedDisposable Members - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - public void Dispose() - { - lock (_db.SyncLock) - { - if (_con != null) - { - List pool = _db.CommandsPool.TryGetValue(_con.Connection); - - if (pool != null && pool.Contains(this)) - pool.Remove(this); - } - - IsDisposed = true; - - if (_command != null) - { - _command.Parameters.Clear(); - - _command.Dispose(); - _command = null; - } - } - } + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + if (IsDisposed) + return; + + var db = _db; + if (db == null) + { + IsDisposed = true; + return; + } + + lock (db.SyncLock) + { + if (IsDisposed) + return; + + IsDisposed = true; + + if (_con != null) + { + List pool = db.CommandsPool.TryGetValue(_con.Connection); + + if (pool != null && pool.Contains(this)) + pool.Remove(this); + } + + if (_command != null) + { + _command.Parameters.Clear(); + + _command.Dispose(); + _command = null; + } + + _con = null; + _db = null; + } + } /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } #endregion IExtendedDisposable Members } -} \ No newline at end of file +} diff --git a/DynamORM/DynamicConnection.cs b/DynamORM/DynamicConnection.cs index 346083a..a948786 100644 --- a/DynamORM/DynamicConnection.cs +++ b/DynamORM/DynamicConnection.cs @@ -161,17 +161,25 @@ namespace DynamORM #region IExtendedDisposable Members - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - public void Dispose() - { - _db.Close(Connection); - IsDisposed = true; - } + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + public void Dispose() + { + if (IsDisposed) + return; + + var db = _db; + if (db != null && Connection != null) + db.Close(Connection); + + Connection = null; + _db = null; + IsDisposed = true; + } /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } #endregion IExtendedDisposable Members } -} \ No newline at end of file +} diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs index c54be39..f627e4e 100644 --- a/DynamORM/DynamicDatabase.cs +++ b/DynamORM/DynamicDatabase.cs @@ -2006,13 +2006,16 @@ namespace DynamORM #region IExtendedDisposable Members - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - public void Dispose() - { -#if !DYNAMORM_OMMIT_OLDSYNTAX - List tables = TablesCache.Values.ToList(); - TablesCache.Clear(); + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + public void Dispose() + { + if (IsDisposed) + return; + +#if !DYNAMORM_OMMIT_OLDSYNTAX + List tables = TablesCache.Values.ToList(); + TablesCache.Clear(); tables.ForEach(t => t.Dispose()); tables.Clear(); @@ -2063,16 +2066,18 @@ namespace DynamORM RemainingBuilders = null; } - ClearSchema(); - if (_proc != null) - _proc.Dispose(); - - IsDisposed = true; - } + ClearSchema(); + if (_proc != null) + _proc.Dispose(); + + _proc = null; + _tempConn = null; + IsDisposed = true; + } /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } #endregion IExtendedDisposable Members } -} \ No newline at end of file +} diff --git a/DynamORM/DynamicProcedureInvoker.cs b/DynamORM/DynamicProcedureInvoker.cs index 1f71167..14f0770 100644 --- a/DynamORM/DynamicProcedureInvoker.cs +++ b/DynamORM/DynamicProcedureInvoker.cs @@ -51,10 +51,11 @@ namespace DynamORM /// public class ProcResult { [Column("outp")] public Guid Output { get; set; } } /// ProcResult res4 = db.Procedures.sp_Test_Scalar_In_Out<ProcResult>(inp: Guid.NewGuid(), out_outp: Guid.Empty) as ProcResult; /// As you can se, you can use mapper to do job for you. - public class DynamicProcedureInvoker : DynamicObject, IDisposable - { - private DynamicDatabase _db; - private List _prefixes; + public class DynamicProcedureInvoker : DynamicObject, IDisposable + { + private DynamicDatabase _db; + private List _prefixes; + private bool _isDisposed; internal DynamicProcedureInvoker(DynamicDatabase db, List prefixes = null) { @@ -446,10 +447,16 @@ namespace DynamORM return true; } - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - public void Dispose() - { - } - } -} \ No newline at end of file + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + if (_isDisposed) + return; + + _isDisposed = true; + _db = null; + _prefixes = null; + } + } +} diff --git a/DynamORM/DynamicTable.cs b/DynamORM/DynamicTable.cs index ab28af1..7c7ab4b 100644 --- a/DynamORM/DynamicTable.cs +++ b/DynamORM/DynamicTable.cs @@ -950,15 +950,18 @@ namespace DynamORM #region IExtendedDisposable Members - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - public void Dispose() - { - // Lose reference but don't kill it. - if (Database != null) - { - Database.RemoveFromCache(this); - Database = null; + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + if (IsDisposed) + return; + + // Lose reference but don't kill it. + if (Database != null) + { + Database.RemoveFromCache(this); + Database = null; } IsDisposed = true; @@ -989,4 +992,4 @@ namespace DynamORM } #endif -} \ No newline at end of file +} diff --git a/DynamORM/DynamicTransaction.cs b/DynamORM/DynamicTransaction.cs index ea0747b..6f0a697 100644 --- a/DynamORM/DynamicTransaction.cs +++ b/DynamORM/DynamicTransaction.cs @@ -170,20 +170,27 @@ namespace DynamORM #region IExtendedDisposable Members - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - public void Dispose() - { - _isDisposed = true; - Rollback(); - - if (_disposed != null) - _disposed(); - } + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + if (_isDisposed) + return; + + _isDisposed = true; + Rollback(); + + if (_disposed != null) + _disposed(); + + _disposed = null; + _con = null; + _db = null; + } /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get { return !_isOperational; } } #endregion IExtendedDisposable Members } -} \ No newline at end of file +} diff --git a/DynamORM/Helpers/Dynamics/DynamicParser.cs b/DynamORM/Helpers/Dynamics/DynamicParser.cs index 972bcd6..b1c7792 100644 --- a/DynamORM/Helpers/Dynamics/DynamicParser.cs +++ b/DynamORM/Helpers/Dynamics/DynamicParser.cs @@ -1444,15 +1444,18 @@ namespace DynamORM.Helpers.Dynamics /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - IsDisposed = true; - - if (_uncertainResult != null) - { + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + if (IsDisposed) + return; + + IsDisposed = true; + + if (_uncertainResult != null) + { if (_uncertainResult is Node) ((Node)_uncertainResult).Dispose(); @@ -1486,4 +1489,4 @@ namespace DynamORM.Helpers.Dynamics #endregion Implementation of IExtendedDisposable } -} \ No newline at end of file +}