diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs
index 187b7f3..e6ac6b5 100644
--- a/AmalgamationTool/DynamORM.Amalgamation.cs
+++ b/AmalgamationTool/DynamORM.Amalgamation.cs
@@ -773,7 +773,10 @@ namespace DynamORM
IsDisposed = true;
+ _command.Parameters.Clear();
+
_command.Dispose();
+ _command = null;
}
}
@@ -980,6 +983,9 @@ namespace DynamORM
/// Gets schema columns cache.
internal Dictionary> Schema { get; private set; }
+ /// Gets active builders that weren't disposed.
+ internal List RemainingBuilders { get; private set; }
+
#if !DYNAMORM_OMMIT_OLDSYNTAX
/// Gets tables cache for this database instance.
@@ -1050,6 +1056,7 @@ namespace DynamORM
TransactionPool = new Dictionary>();
CommandsPool = new Dictionary>();
Schema = new Dictionary>();
+ RemainingBuilders = new List();
#if !DYNAMORM_OMMIT_OLDSYNTAX
TablesCache = new Dictionary();
#endif
@@ -1134,6 +1141,22 @@ namespace DynamORM
#endregion Table
+ /// Adds cached builder.
+ /// New dynamic builder.
+ internal void AddToCache(IDynamicQueryBuilder builder)
+ {
+ lock (SyncLock)
+ RemainingBuilders.Add(builder);
+ }
+
+ /// Removes cached builder.
+ /// Disposed dynamic builder.
+ internal void RemoveFromCache(IDynamicQueryBuilder builder)
+ {
+ lock (SyncLock)
+ RemainingBuilders.Remove(builder);
+ }
+
#region From/Insert/Update/Delete
///
@@ -1846,7 +1869,11 @@ namespace DynamORM
{
lock (SyncLock)
if (Schema.ContainsKey(table.FullName))
+ {
+ if (Schema[table.FullName] != null)
+ Schema[table.FullName].Clear();
Schema.Remove(table.FullName);
+ }
}
/// Clears the all schemas from cache.
@@ -1854,7 +1881,13 @@ namespace DynamORM
public void ClearSchema()
{
lock (SyncLock)
+ {
+ foreach (var s in Schema)
+ if (s.Value != null)
+ s.Value.Clear();
+
Schema.Clear();
+ }
}
/// Get schema describing objects from reader.
@@ -2175,6 +2208,7 @@ namespace DynamORM
// Dispose the corpse
connection.Dispose();
+ connection = null;
}
}
@@ -2268,6 +2302,8 @@ namespace DynamORM
TablesCache.Clear();
tables.ForEach(t => t.Dispose());
+ tables.Clear();
+ tables = null;
#endif
foreach (var con in TransactionPool)
@@ -2279,6 +2315,8 @@ namespace DynamORM
tmp.ForEach(cmd => cmd.Dispose());
CommandsPool[con.Key].Clear();
+ tmp.Clear();
+ CommandsPool[con.Key] = tmp = null;
}
// Rollback remaining transactions
@@ -2297,13 +2335,23 @@ namespace DynamORM
con.Key.Dispose();
}
+ while (RemainingBuilders.Count > 0)
+ RemainingBuilders.First().Dispose();
+
// Clear pools
lock (SyncLock)
{
TransactionPool.Clear();
CommandsPool.Clear();
+ RemainingBuilders.Clear();
+
+ TransactionPool = null;
+ CommandsPool = null;
+ RemainingBuilders = null;
}
+ ClearSchema();
+
IsDisposed = true;
}
@@ -5025,7 +5073,7 @@ namespace DynamORM
/// Dynamic query builder base interface.
/// This interface it publically available. Implementation should be hidden.
- public interface IDynamicQueryBuilder
+ public interface IDynamicQueryBuilder : IExtendedDisposable
{
/// Gets instance.
DynamicDatabase Database { get; }
@@ -5357,7 +5405,7 @@ namespace DynamORM
}
/// Interface describing parameter info.
- public interface IParameter
+ public interface IParameter : IExtendedDisposable
{
/// Gets the parameter position in command.
/// Available after filling the command.
@@ -5380,7 +5428,7 @@ namespace DynamORM
}
/// Interface describing table information.
- public interface ITableInfo
+ public interface ITableInfo : IExtendedDisposable
{
/// Gets table owner name.
string Owner { get; }
@@ -5988,6 +6036,19 @@ namespace DynamORM
}
#endregion Insert
+
+ #region IExtendedDisposable
+
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ _columns = _values = null;
+ }
+
+ #endregion IExtendedDisposable
}
/// Base query builder for insert/update/delete statements.
@@ -6054,6 +6115,7 @@ namespace DynamORM
///
internal TableInfo()
{
+ IsDisposed = false;
}
///
@@ -6064,6 +6126,7 @@ namespace DynamORM
/// The table alias.
/// The table owner.
public TableInfo(DynamicDatabase db, string name, string alias = null, string owner = null)
+ : this()
{
Name = name;
Alias = alias;
@@ -6081,6 +6144,7 @@ namespace DynamORM
/// The table alias.
/// The table owner.
public TableInfo(DynamicDatabase db, Type type, string alias = null, string owner = null)
+ : this()
{
var mapper = DynamicMapperCache.GetMapper(type);
@@ -6104,6 +6168,20 @@ namespace DynamORM
/// Gets or sets table schema.
public Dictionary Schema { get; internal set; }
+
+ /// 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;
+
+ Schema.Clear();
+ Owner = Name = Alias = null;
+ Schema = null;
+ }
}
/// Generic based table information.
@@ -6129,6 +6207,13 @@ namespace DynamORM
/// Interface describing parameter info.
internal class Parameter : IParameter
{
+ /// Initializes a new instance of the
+ /// class.
+ public Parameter()
+ {
+ IsDisposed = false;
+ }
+
/// Gets or sets the parameter position in command.
/// Available after filling the command.
public int Ordinal { get; internal set; }
@@ -6147,6 +6232,19 @@ namespace DynamORM
/// Gets or sets the parameter schema information.
public DynamicSchemaColumn? Schema { get; set; }
+
+ /// 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;
+
+ Name = null;
+ Schema = null;
+ }
}
#endregion Parameter
@@ -6159,6 +6257,7 @@ namespace DynamORM
/// The database.
public DynamicQueryBuilder(DynamicDatabase db)
{
+ IsDisposed = false;
VirtualMode = false;
Tables = new List();
Parameters = new Dictionary();
@@ -6167,6 +6266,9 @@ namespace DynamORM
OpenBracketsCount = 0;
Database = db;
+ if (Database != null)
+ Database.AddToCache(this);
+
SupportSchema = (db.Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema;
}
@@ -6318,7 +6420,9 @@ namespace DynamORM
// If node is a delegate, parse it to create the logical tree...
if (node is Delegate)
{
- node = DynamicParser.Parse((Delegate)node).Result;
+ using (var p = DynamicParser.Parse((Delegate)node))
+ node = p.Result;
+
return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string")
}
@@ -6801,6 +6905,44 @@ namespace DynamORM
}
#endregion Helpers
+
+ #region IExtendedDisposable
+
+ /// 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);
+
+ if (Parameters != null)
+ {
+ foreach (var p in Parameters)
+ p.Value.Dispose();
+
+ Parameters.Clear();
+ Parameters = null;
+ }
+
+ if (Tables != null)
+ {
+ foreach (var t in Tables)
+ t.Dispose();
+
+ Tables.Clear();
+ Tables = null;
+ }
+
+ WhereCondition = null;
+ Database = null;
+ }
+
+ #endregion IExtendedDisposable
}
/// Implementation of dynamic select query builder.
@@ -8060,6 +8202,19 @@ namespace DynamORM
}
#endregion Helpers
+
+ #region IExtendedDisposable
+
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ _select = _from = _join = _groupby = _orderby = null;
+ }
+
+ #endregion IExtendedDisposable
}
/// Update query builder.
@@ -8190,7 +8345,11 @@ namespace DynamORM
index++;
if (f == null)
throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index));
- var result = DynamicParser.Parse(f).Result;
+
+ object result = null;
+
+ using (var p = DynamicParser.Parse(f))
+ result = p.Result;
if (result == null)
throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index));
@@ -8343,6 +8502,19 @@ namespace DynamORM
}
#endregion Where
+
+ #region IExtendedDisposable
+
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ _columns = null;
+ }
+
+ #endregion IExtendedDisposable
}
}
}
@@ -8930,6 +9102,8 @@ namespace DynamORM
[Serializable]
public class Node : IDynamicMetaObjectProvider, IExtendedDisposable, ISerializable
{
+ private DynamicParser _parser = null;
+
#region MetaNode
///
@@ -9639,6 +9813,23 @@ namespace DynamORM
return string.Format("({0} {1} {2})", Host.Sketch(), Operation, Right.Sketch());
}
+
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ if (Right != null && Right is Node)
+ {
+ Node n = (Node)Right;
+
+ if (!n.IsDisposed)
+ n.Dispose();
+
+ Right = null;
+ }
+ }
}
#endregion Binary
@@ -9765,7 +9956,16 @@ namespace DynamORM
public Node Host { get; internal set; }
/// Gets reference to the parser.
- public DynamicParser Parser { get; internal set; }
+ public DynamicParser Parser
+ {
+ get { return _parser; }
+ internal set
+ {
+ _parser = value;
+ if (_parser != null)
+ _parser._allNodes.Add(this);
+ }
+ }
///
/// Initializes a new instance of the class.
@@ -9858,12 +10058,18 @@ namespace DynamORM
/// 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()
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ public virtual void Dispose()
{
IsDisposed = true;
+
+ if (Host != null && !Host.IsDisposed)
+ Host.Dispose();
+
+ Host = null;
+
+ Parser = null;
}
#endregion Implementation of IExtendedDisposable
@@ -9893,6 +10099,7 @@ namespace DynamORM
#region Data
private List _arguments = new List();
+ private List _allNodes = new List();
private object _uncertainResult;
#endregion Data
@@ -10005,6 +10212,34 @@ namespace DynamORM
public void Dispose()
{
IsDisposed = true;
+
+ if (_uncertainResult != null && _uncertainResult is Node)
+ {
+ ((Node)_uncertainResult).Dispose();
+ _uncertainResult = null;
+ }
+
+ if (Last != null && !Last.IsDisposed)
+ {
+ Last.Dispose();
+ Last = null;
+ }
+
+ if (_arguments != null)
+ {
+ _arguments.ForEach(x => { if (!x.IsDisposed) x.Dispose(); });
+
+ _arguments.Clear();
+ _arguments = null;
+ }
+
+ if (_allNodes != null)
+ {
+ _allNodes.ForEach(x => { if (!x.IsDisposed) x.Dispose(); });
+
+ _allNodes.Clear();
+ _allNodes = null;
+ }
}
#endregion Implementation of IExtendedDisposable
@@ -10013,7 +10248,7 @@ namespace DynamORM
/// Class that allows to use interfaces as dynamic objects.
/// Type of class to proxy.
/// This is temporary solution. Which allows to use builders as a dynamic type.
- public class DynamicProxy : DynamicObject
+ public class DynamicProxy : DynamicObject, IDisposable
{
private T _proxy;
private Type _type;
@@ -10033,15 +10268,15 @@ namespace DynamORM
_proxy = proxiedObject;
_type = typeof(T);
- var members = GetAllMembers(_type);
+ var mapper = Mapper.DynamicMapperCache.GetMapper();
- _properties = members
- .Where(x => x is PropertyInfo)
+ _properties = mapper
+ .ColumnsMap
.ToDictionary(
- k => k.Name,
- v => new DynamicPropertyInvoker((PropertyInfo)v, null));
+ k => k.Value.Name,
+ v => v.Value);
- _methods = members
+ _methods = GetAllMembers(_type)
.Where(x => x is MethodInfo)
.Cast()
.Where(m => !((m.Name.StartsWith("set_") && m.ReturnType == typeof(void)) || m.Name.StartsWith("get_")))
@@ -10286,6 +10521,21 @@ namespace DynamORM
return type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
}
+
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ public void Dispose()
+ {
+ object res;
+ TryInvokeMethod("Dispose", out res, new object[] { });
+
+ _properties.Clear();
+
+ _methods = null;
+ _properties = null;
+ _type = null;
+ _proxy = default(T);
+ }
}
}
}
@@ -10654,7 +10904,7 @@ namespace DynamORM
var propertyMap = new Dictionary();
var ignored = new List();
- foreach (var pi in Type.GetProperties())
+ foreach (var pi in GetAllMembers(Type).Where(x => x is PropertyInfo).Cast())
{
ColumnAttribute attr = null;
@@ -10714,6 +10964,46 @@ namespace DynamORM
return destination;
}
+ private IEnumerable GetAllMembers(Type type)
+ {
+ if (type.IsInterface)
+ {
+ var members = new List();
+
+ var considered = new List();
+ var queue = new Queue();
+
+ considered.Add(type);
+ queue.Enqueue(type);
+
+ while (queue.Count > 0)
+ {
+ var subType = queue.Dequeue();
+ foreach (var subInterface in subType.GetInterfaces())
+ {
+ if (considered.Contains(subInterface)) continue;
+
+ considered.Add(subInterface);
+ queue.Enqueue(subInterface);
+ }
+
+ var typeProperties = subType.GetMembers(
+ BindingFlags.FlattenHierarchy
+ | BindingFlags.Public
+ | BindingFlags.Instance);
+
+ var newPropertyInfos = typeProperties
+ .Where(x => !members.Contains(x));
+
+ members.InsertRange(0, newPropertyInfos);
+ }
+
+ return members;
+ }
+
+ return type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
+ }
+
#region Type command cache
internal string InsertCommandText { get; set; }
diff --git a/DynamORM/Helpers/Dynamics/DynamicProxy.cs b/DynamORM/Helpers/Dynamics/DynamicProxy.cs
index 9907414..7648223 100644
--- a/DynamORM/Helpers/Dynamics/DynamicProxy.cs
+++ b/DynamORM/Helpers/Dynamics/DynamicProxy.cs
@@ -67,9 +67,7 @@ namespace DynamORM.Helpers.Dynamics
k => k.Value.Name,
v => v.Value);
- _methods = mapper.MethodsMap;
-
- /*GetAllMembers(_type)
+ _methods = GetAllMembers(_type)
.Where(x => x is MethodInfo)
.Cast()
.Where(m => !((m.Name.StartsWith("set_") && m.ReturnType == typeof(void)) || m.Name.StartsWith("get_")))
@@ -86,7 +84,7 @@ namespace DynamORM.Helpers.Dynamics
{
return null;
}
- });*/
+ });
}
/// Provides implementation for type conversion operations.
@@ -238,7 +236,7 @@ namespace DynamORM.Helpers.Dynamics
if (d != null)
{
- result = d.DynamicInvoke(CompleteArguments(mi.GetParameters().ToArray(), args).ToArray());
+ result = d.DynamicInvoke(CompleteArguments(mi.GetParameters().ToArray(), args));
if (d.Method.ReturnType == _type && result is T)
result = new DynamicProxy((T)result);
@@ -247,7 +245,7 @@ namespace DynamORM.Helpers.Dynamics
}
else if (mi != null)
{
- result = mi.Invoke(_proxy, CompleteArguments(mi.GetParameters().ToArray(), args).Skip(1).ToArray());
+ result = mi.Invoke(_proxy, CompleteArguments(mi.GetParameters().ToArray(), args));
if (mi.ReturnType == _type && result is T)
result = new DynamicProxy((T)result);
@@ -270,9 +268,9 @@ namespace DynamORM.Helpers.Dynamics
return true;
}
- private IEnumerable