diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs
index ec9e88b..b1f55a9 100644
--- a/AmalgamationTool/DynamORM.Amalgamation.cs
+++ b/AmalgamationTool/DynamORM.Amalgamation.cs
@@ -805,11 +805,12 @@ namespace DynamORM
/// Begins a database transaction.
/// One of the values.
+ /// Custom parameter describing transaction options.
/// This action is invoked when transaction is disposed.
/// Returns representation.
- internal DynamicTransaction BeginTransaction(IsolationLevel? il, Action disposed)
+ internal DynamicTransaction BeginTransaction(IsolationLevel? il, object custom, Action disposed)
{
- return new DynamicTransaction(_db, this, _singleTransaction, il, disposed);
+ return new DynamicTransaction(_db, this, _singleTransaction, il, disposed, null);
}
#region IDbConnection Members
@@ -825,7 +826,7 @@ namespace DynamORM
/// Returns representation.
public IDbTransaction BeginTransaction()
{
- return BeginTransaction(null, null);
+ return BeginTransaction(null, null, null);
}
/// Begins a database transaction with the specified
@@ -834,7 +835,16 @@ namespace DynamORM
/// Returns representation.
public IDbTransaction BeginTransaction(IsolationLevel il)
{
- return BeginTransaction(il, null);
+ return BeginTransaction(il, null, null);
+ }
+
+ /// Begins a database transaction with the specified
+ /// value.
+ /// Custom parameter describing transaction options.
+ /// Returns representation.
+ public IDbTransaction BeginTransaction(object custom)
+ {
+ return BeginTransaction(null, custom, null);
}
/// Changes the current database for an open Connection object.
@@ -1733,6 +1743,31 @@ namespace DynamORM
#region Schema
+ /// Builds query cache if necessary and returns it.
+ /// The builder containing query to read schema from.
+ /// Query schema.
+ public Dictionary GetQuerySchema(IDynamicSelectQueryBuilder builder)
+ {
+ using (var con = Open())
+ using (var cmd = con.CreateCommand().SetCommand(builder))
+ return ReadSchema(cmd)
+ .Distinct()
+ .ToDictionary(k => k.Name.ToLower(), k => k);
+ }
+
+ /// Builds query cache if necessary and returns it.
+ /// Sql query from which read schema.
+ /// Sql query argumants.
+ /// Query schema.
+ public Dictionary GetQuerySchema(string sql, params object[] args)
+ {
+ using (var con = Open())
+ using (var cmd = con.CreateCommand().SetCommand(sql, args))
+ return ReadSchema(cmd)
+ .Distinct()
+ .ToDictionary(k => k.Name.ToLower(), k => k);
+ }
+
/// Builds table cache if necessary and returns it.
/// Name of table for which build schema.
/// Owner of table for which build schema.
@@ -1790,29 +1825,35 @@ namespace DynamORM
protected virtual IEnumerable ReadSchema(string table, string owner)
{
using (var con = Open())
- using (var cmd = con.CreateCommand())
- {
- using (var rdr = cmd
- .SetCommand(string.Format("SELECT * FROM {0}{1} WHERE 1 = 0",
- !string.IsNullOrEmpty(owner) ? string.Format("{0}.", DecorateName(owner)) : string.Empty,
- DecorateName(table)))
- .ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo))
- foreach (DataRow col in rdr.GetSchemaTable().Rows)
- {
- var c = col.RowToDynamicUpper();
+ using (var cmd = con.CreateCommand()
+ .SetCommand(string.Format("SELECT * FROM {0}{1} WHERE 1 = 0",
+ !string.IsNullOrEmpty(owner) ? string.Format("{0}.", DecorateName(owner)) : string.Empty,
+ DecorateName(table))))
+ return ReadSchema(cmd);
+ }
- yield return new DynamicSchemaColumn
- {
- Name = c.COLUMNNAME,
- Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String,
- IsKey = c.ISKEY ?? false,
- IsUnique = c.ISUNIQUE ?? false,
- Size = (int)(c.COLUMNSIZE ?? 0),
- Precision = (byte)(c.NUMERICPRECISION ?? 0),
- Scale = (byte)(c.NUMERICSCALE ?? 0)
- };
- }
- }
+ /// Get schema describing objects from reader.
+ /// Command containing query to execute.
+ /// List of objects .
+ /// If your database doesn't get those values in upper case (like most of the databases) you should override this method.
+ protected virtual IEnumerable ReadSchema(IDbCommand cmd)
+ {
+ using (var rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo))
+ foreach (DataRow col in rdr.GetSchemaTable().Rows)
+ {
+ var c = col.RowToDynamicUpper();
+
+ yield return new DynamicSchemaColumn
+ {
+ Name = c.COLUMNNAME,
+ Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String,
+ IsKey = c.ISKEY ?? false,
+ IsUnique = c.ISUNIQUE ?? false,
+ Size = (int)(c.COLUMNSIZE ?? 0),
+ Precision = (byte)(c.NUMERICPRECISION ?? 0),
+ Scale = (byte)(c.NUMERICSCALE ?? 0)
+ };
+ }
}
private Dictionary BuildAndCacheSchema(string tableName, DynamicTypeMap mapper, string owner = null)
@@ -1832,6 +1873,7 @@ namespace DynamORM
if (databaseSchemaSupport && !Schema.ContainsKey(tableName.ToLower()))
{
schema = ReadSchema(tableName, owner)
+ .Distinct()
.ToDictionary(k => k.Name.ToLower(), k => k);
Schema[tableName.ToLower()] = schema;
@@ -2110,7 +2152,47 @@ namespace DynamORM
{
_tempConn = Open() as DynamicConnection;
- return _tempConn.BeginTransaction(null, () =>
+ return _tempConn.BeginTransaction(null, null, () =>
+ {
+ var t = TransactionPool.TryGetValue(_tempConn.Connection);
+
+ if (t == null | t.Count == 0)
+ {
+ _tempConn.Dispose();
+ _tempConn = null;
+ }
+ });
+ }
+
+ /// Begins a database transaction with the specified
+ /// value.
+ /// One of the values.
+ /// Returns representation.
+ public IDbTransaction BeginTransaction(IsolationLevel il)
+ {
+ _tempConn = Open() as DynamicConnection;
+
+ return _tempConn.BeginTransaction(il, null, () =>
+ {
+ var t = TransactionPool.TryGetValue(_tempConn.Connection);
+
+ if (t == null | t.Count == 0)
+ {
+ _tempConn.Dispose();
+ _tempConn = null;
+ }
+ });
+ }
+
+ /// Begins a database transaction with the specified
+ /// value.
+ /// Custom parameter describing transaction options.
+ /// Returns representation.
+ public IDbTransaction BeginTransaction(object custom)
+ {
+ _tempConn = Open() as DynamicConnection;
+
+ return _tempConn.BeginTransaction(null, custom, () =>
{
var t = TransactionPool.TryGetValue(_tempConn.Connection);
@@ -4658,7 +4740,8 @@ namespace DynamORM
/// Are we using single transaction mode? I so... act correctly.
/// One of the values.
/// This action is invoked when transaction is disposed.
- internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed)
+ /// Pass custom transaction parameters.
+ internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed, object customParams)
{
_db = db;
_con = con;
@@ -4673,8 +4756,19 @@ namespace DynamORM
_operational = false;
else
{
- _db.TransactionPool[_con.Connection]
- .Push(il.HasValue ? _con.Connection.BeginTransaction(il.Value) : _con.Connection.BeginTransaction());
+ if (customParams != null)
+ {
+ var mi = _con.Connection.GetType().GetMethods().Where(m => m.GetParameters().Count() == 1 && m.GetParameters().First().ParameterType == customParams.GetType()).FirstOrDefault();
+ if (mi != null)
+ _db.TransactionPool[_con.Connection].Push((IDbTransaction)mi.Invoke(_con.Connection, new object[] { customParams, }));
+ else
+ throw new MissingMethodException(string.Format("Method 'BeginTransaction' accepting parameter of type '{0}' in '{1}' not found.",
+ customParams.GetType().FullName, _con.Connection.GetType().FullName));
+ }
+ else
+ _db.TransactionPool[_con.Connection]
+ .Push(il.HasValue ? _con.Connection.BeginTransaction(il.Value) : _con.Connection.BeginTransaction());
+
_db.PoolStamp = DateTime.Now.Ticks;
_operational = true;
}
diff --git a/DynamORM.Tests/DynamORM.Tests.csproj b/DynamORM.Tests/DynamORM.Tests.csproj
index 2772e40..384ca3d 100644
--- a/DynamORM.Tests/DynamORM.Tests.csproj
+++ b/DynamORM.Tests/DynamORM.Tests.csproj
@@ -105,6 +105,7 @@
ResXFileCodeGenerator
Resources.Designer.cs
+ Designer
diff --git a/DynamORM/DynamicConnection.cs b/DynamORM/DynamicConnection.cs
index 2e4cb0a..dd84cd0 100644
--- a/DynamORM/DynamicConnection.cs
+++ b/DynamORM/DynamicConnection.cs
@@ -57,11 +57,12 @@ namespace DynamORM
/// Begins a database transaction.
/// One of the values.
+ /// Custom parameter describing transaction options.
/// This action is invoked when transaction is disposed.
/// Returns representation.
- internal DynamicTransaction BeginTransaction(IsolationLevel? il, Action disposed)
+ internal DynamicTransaction BeginTransaction(IsolationLevel? il, object custom, Action disposed)
{
- return new DynamicTransaction(_db, this, _singleTransaction, il, disposed);
+ return new DynamicTransaction(_db, this, _singleTransaction, il, disposed, null);
}
#region IDbConnection Members
@@ -77,7 +78,7 @@ namespace DynamORM
/// Returns representation.
public IDbTransaction BeginTransaction()
{
- return BeginTransaction(null, null);
+ return BeginTransaction(null, null, null);
}
/// Begins a database transaction with the specified
@@ -86,7 +87,16 @@ namespace DynamORM
/// Returns representation.
public IDbTransaction BeginTransaction(IsolationLevel il)
{
- return BeginTransaction(il, null);
+ return BeginTransaction(il, null, null);
+ }
+
+ /// Begins a database transaction with the specified
+ /// value.
+ /// Custom parameter describing transaction options.
+ /// Returns representation.
+ public IDbTransaction BeginTransaction(object custom)
+ {
+ return BeginTransaction(null, custom, null);
}
/// Changes the current database for an open Connection object.
diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs
index f31632c..9f54c2c 100644
--- a/DynamORM/DynamicDatabase.cs
+++ b/DynamORM/DynamicDatabase.cs
@@ -860,6 +860,31 @@ namespace DynamORM
#region Schema
+ /// Builds query cache if necessary and returns it.
+ /// The builder containing query to read schema from.
+ /// Query schema.
+ public Dictionary GetQuerySchema(IDynamicSelectQueryBuilder builder)
+ {
+ using (var con = Open())
+ using (var cmd = con.CreateCommand().SetCommand(builder))
+ return ReadSchema(cmd)
+ .Distinct()
+ .ToDictionary(k => k.Name.ToLower(), k => k);
+ }
+
+ /// Builds query cache if necessary and returns it.
+ /// Sql query from which read schema.
+ /// Sql query argumants.
+ /// Query schema.
+ public Dictionary GetQuerySchema(string sql, params object[] args)
+ {
+ using (var con = Open())
+ using (var cmd = con.CreateCommand().SetCommand(sql, args))
+ return ReadSchema(cmd)
+ .Distinct()
+ .ToDictionary(k => k.Name.ToLower(), k => k);
+ }
+
/// Builds table cache if necessary and returns it.
/// Name of table for which build schema.
/// Owner of table for which build schema.
@@ -917,29 +942,35 @@ namespace DynamORM
protected virtual IEnumerable ReadSchema(string table, string owner)
{
using (var con = Open())
- using (var cmd = con.CreateCommand())
- {
- using (var rdr = cmd
- .SetCommand(string.Format("SELECT * FROM {0}{1} WHERE 1 = 0",
- !string.IsNullOrEmpty(owner) ? string.Format("{0}.", DecorateName(owner)) : string.Empty,
- DecorateName(table)))
- .ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo))
- foreach (DataRow col in rdr.GetSchemaTable().Rows)
- {
- var c = col.RowToDynamicUpper();
+ using (var cmd = con.CreateCommand()
+ .SetCommand(string.Format("SELECT * FROM {0}{1} WHERE 1 = 0",
+ !string.IsNullOrEmpty(owner) ? string.Format("{0}.", DecorateName(owner)) : string.Empty,
+ DecorateName(table))))
+ return ReadSchema(cmd);
+ }
- yield return new DynamicSchemaColumn
- {
- Name = c.COLUMNNAME,
- Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String,
- IsKey = c.ISKEY ?? false,
- IsUnique = c.ISUNIQUE ?? false,
- Size = (int)(c.COLUMNSIZE ?? 0),
- Precision = (byte)(c.NUMERICPRECISION ?? 0),
- Scale = (byte)(c.NUMERICSCALE ?? 0)
- };
- }
- }
+ /// Get schema describing objects from reader.
+ /// Command containing query to execute.
+ /// List of objects .
+ /// If your database doesn't get those values in upper case (like most of the databases) you should override this method.
+ protected virtual IEnumerable ReadSchema(IDbCommand cmd)
+ {
+ using (var rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo))
+ foreach (DataRow col in rdr.GetSchemaTable().Rows)
+ {
+ var c = col.RowToDynamicUpper();
+
+ yield return new DynamicSchemaColumn
+ {
+ Name = c.COLUMNNAME,
+ Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String,
+ IsKey = c.ISKEY ?? false,
+ IsUnique = c.ISUNIQUE ?? false,
+ Size = (int)(c.COLUMNSIZE ?? 0),
+ Precision = (byte)(c.NUMERICPRECISION ?? 0),
+ Scale = (byte)(c.NUMERICSCALE ?? 0)
+ };
+ }
}
private Dictionary BuildAndCacheSchema(string tableName, DynamicTypeMap mapper, string owner = null)
@@ -959,6 +990,7 @@ namespace DynamORM
if (databaseSchemaSupport && !Schema.ContainsKey(tableName.ToLower()))
{
schema = ReadSchema(tableName, owner)
+ .Distinct()
.ToDictionary(k => k.Name.ToLower(), k => k);
Schema[tableName.ToLower()] = schema;
@@ -1237,7 +1269,47 @@ namespace DynamORM
{
_tempConn = Open() as DynamicConnection;
- return _tempConn.BeginTransaction(null, () =>
+ return _tempConn.BeginTransaction(null, null, () =>
+ {
+ var t = TransactionPool.TryGetValue(_tempConn.Connection);
+
+ if (t == null | t.Count == 0)
+ {
+ _tempConn.Dispose();
+ _tempConn = null;
+ }
+ });
+ }
+
+ /// Begins a database transaction with the specified
+ /// value.
+ /// One of the values.
+ /// Returns representation.
+ public IDbTransaction BeginTransaction(IsolationLevel il)
+ {
+ _tempConn = Open() as DynamicConnection;
+
+ return _tempConn.BeginTransaction(il, null, () =>
+ {
+ var t = TransactionPool.TryGetValue(_tempConn.Connection);
+
+ if (t == null | t.Count == 0)
+ {
+ _tempConn.Dispose();
+ _tempConn = null;
+ }
+ });
+ }
+
+ /// Begins a database transaction with the specified
+ /// value.
+ /// Custom parameter describing transaction options.
+ /// Returns representation.
+ public IDbTransaction BeginTransaction(object custom)
+ {
+ _tempConn = Open() as DynamicConnection;
+
+ return _tempConn.BeginTransaction(null, custom, () =>
{
var t = TransactionPool.TryGetValue(_tempConn.Connection);
diff --git a/DynamORM/DynamicTransaction.cs b/DynamORM/DynamicTransaction.cs
index 75b947f..29aadae 100644
--- a/DynamORM/DynamicTransaction.cs
+++ b/DynamORM/DynamicTransaction.cs
@@ -28,6 +28,7 @@
using System;
using System.Data;
+using System.Linq;
using DynamORM.Helpers;
namespace DynamORM
@@ -47,7 +48,8 @@ namespace DynamORM
/// Are we using single transaction mode? I so... act correctly.
/// One of the values.
/// This action is invoked when transaction is disposed.
- internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed)
+ /// Pass custom transaction parameters.
+ internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed, object customParams)
{
_db = db;
_con = con;
@@ -62,8 +64,19 @@ namespace DynamORM
_operational = false;
else
{
- _db.TransactionPool[_con.Connection]
- .Push(il.HasValue ? _con.Connection.BeginTransaction(il.Value) : _con.Connection.BeginTransaction());
+ if (customParams != null)
+ {
+ var mi = _con.Connection.GetType().GetMethods().Where(m => m.GetParameters().Count() == 1 && m.GetParameters().First().ParameterType == customParams.GetType()).FirstOrDefault();
+ if (mi != null)
+ _db.TransactionPool[_con.Connection].Push((IDbTransaction)mi.Invoke(_con.Connection, new object[] { customParams, }));
+ else
+ throw new MissingMethodException(string.Format("Method 'BeginTransaction' accepting parameter of type '{0}' in '{1}' not found.",
+ customParams.GetType().FullName, _con.Connection.GetType().FullName));
+ }
+ else
+ _db.TransactionPool[_con.Connection]
+ .Push(il.HasValue ? _con.Connection.BeginTransaction(il.Value) : _con.Connection.BeginTransaction());
+
_db.PoolStamp = DateTime.Now.Ticks;
_operational = true;
}