This commit is contained in:
grzegorz.russek
2014-04-04 19:41:51 +00:00
parent f9684f484e
commit 397a8da830
14 changed files with 337 additions and 90 deletions

View File

@@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Data;
namespace DynamORM.Builders
{
@@ -44,10 +45,30 @@ namespace DynamORM.Builders
/// <returns>Enumerator of objects expanded from query.</returns>
IEnumerable<T> Execute<T>() where T : class;
/// <summary>Execute this builder as a data reader.</summary>
/// <param name="reader">Action containing reader.</param>
void ExecuteDataReader(Action<IDataReader> reader);
/// <summary>Returns a single result.</summary>
/// <returns>Result of a query.</returns>
object Scalar();
#region SubQuery
/// <summary>Adds to the 'From' clause of sub query the contents obtained by
/// parsing the dynamic lambda expressions given. The supported formats are:
/// <para>- Resolve to a string: 'x => "Table AS Alias', where the alias part is optional.</para>
/// <para>- Resolve to an expression: 'x => x.Table.As( x.Alias )', where the alias part is optional.</para>
/// <para>- Generic expression: 'x => x( expression ).As( x.Alias )', where the alias part is mandatory. In this
/// case the alias is not annotated.</para>
/// </summary>
/// <param name="subquery">First argument is parent query, second one is a subquery.</param>
/// <param name="func">The specification for subquery.</param>
/// <returns>This instance to permit chaining.</returns>
IDynamicSelectQueryBuilder SubQuery(Action<IDynamicSelectQueryBuilder, IDynamicSelectQueryBuilder> subquery, params Func<dynamic, object>[] func);
#endregion SubQuery
#region From/Join
/// <summary>

View File

@@ -44,7 +44,7 @@ namespace DynamORM.Builders
/// <summary>Gets or sets a value indicating whether name of temporary parameter is well known.</summary>
bool WellKnown { get; set; }
/// <summary>Gets or sets a value indicating whether this <see cref="Parameter"/> is virtual.</summary>
/// <summary>Gets or sets a value indicating whether this <see cref="IParameter"/> is virtual.</summary>
bool Virtual { get; set; }
/// <summary>Gets or sets the parameter schema information.</summary>

View File

@@ -311,7 +311,7 @@ namespace DynamORM.Builders.Implementation
/// <param name="isMultiPart">If set parse argument as alias. This is workaround for AS method.</param>
/// <param name="columnSchema">This parameter is used to determine type of parameter used in query.</param>
/// <returns>A string containing the result of the parsing, along with the parameters extracted in the
/// <see cref="pars" /> instance if such is given.</returns>
/// <paramref name="pars" /> instance if such is given.</returns>
/// <exception cref="System.ArgumentNullException">Null nodes are not accepted.</exception>
internal virtual string Parse(object node, IDictionary<string, IParameter> pars = null, bool rawstr = false, bool nulls = false, bool decorate = true, bool isMultiPart = true, DynamicSchemaColumn? columnSchema = null)
{

View File

@@ -31,6 +31,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using DynamORM.Builders.Extensions;
@@ -147,32 +148,30 @@ namespace DynamORM.Builders.Implementation
{
using (var con = Database.Open())
using (var cmd = con.CreateCommand())
{
using (var rdr = cmd
.SetCommand(this)
.ExecuteReader())
while (rdr.Read())
using (var rdr = cmd
.SetCommand(this)
.ExecuteReader())
while (rdr.Read())
{
dynamic val = null;
// Work around to avoid yield being in try...catchblock:
// http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch
try
{
dynamic val = null;
// Work around to avoid yield being in try...catchblock:
// http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch
try
{
val = rdr.RowToDynamic();
}
catch (ArgumentException argex)
{
var sb = new StringBuilder();
cmd.Dump(sb);
throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb),
argex.InnerException.NullOr(a => a, argex));
}
yield return val;
val = rdr.RowToDynamic();
}
}
catch (ArgumentException argex)
{
var sb = new StringBuilder();
cmd.Dump(sb);
throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb),
argex.InnerException.NullOr(a => a, argex));
}
yield return val;
}
}
/// <summary>Execute this builder and map to given type.</summary>
@@ -215,6 +214,18 @@ namespace DynamORM.Builders.Implementation
}
}
/// <summary>Execute this builder as a data reader.</summary>
/// <param name="reader">Action containing reader.</param>
public virtual void ExecuteDataReader(Action<IDataReader> reader)
{
using (var con = Database.Open())
using (var cmd = con.CreateCommand())
using (var rdr = cmd
.SetCommand(this)
.ExecuteReader())
reader(rdr);
}
/// <summary>Returns a single result.</summary>
/// <returns>Result of a query.</returns>
public virtual object Scalar()
@@ -230,6 +241,34 @@ namespace DynamORM.Builders.Implementation
#endregion Execution
#region Subquery
/// <summary>
/// Adds to the 'From' clause of sub query the contents obtained by
/// parsing the dynamic lambda expressions given. The supported formats are:
/// <para>- Resolve to a string: 'x =&gt; "Table AS Alias', where the alias part is optional.</para>
/// <para>- Resolve to an expression: 'x =&gt; x.Table.As( x.Alias )', where the alias part is optional.</para>
/// <para>- Generic expression: 'x =&gt; x( expression ).As( x.Alias )', where the alias part is mandatory. In this
/// case the alias is not annotated.</para>
/// </summary>
/// <param name="subquery">First argument is parent query, second one is a subquery.</param>
/// <param name="func">The specification for subquery.</param>
/// <returns>
/// This instance to permit chaining.
/// </returns>
public virtual IDynamicSelectQueryBuilder SubQuery(Action<IDynamicSelectQueryBuilder, IDynamicSelectQueryBuilder> subquery, params Func<dynamic, object>[] func)
{
var sub = func == null || func.Length == 0 ? base.SubQuery() : base.SubQuery(func);
subquery(this, sub);
ParseCommand(sub as DynamicQueryBuilder, Parameters);
return this;
}
#endregion Subquery
#region From/Join
/// <summary>
@@ -312,6 +351,12 @@ namespace DynamORM.Builders.Implementation
continue;
}
/*if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "subquery")
{
main = Parse(this.SubQuery(((DynamicParser.Node.Method)node).Arguments.Where(p => p is Func<dynamic, object>).Cast<Func<dynamic, object>>().ToArray()), Parameters);
continue;
}*/
// Support for table specifications...
if (node is DynamicParser.Node.GetMember)
{
@@ -560,7 +605,7 @@ namespace DynamORM.Builders.Implementation
}
// Support for Join Type specifications...
if (node is DynamicParser.Node.Method && node.Host is DynamicParser.Node.Argument)
if (node is DynamicParser.Node.Method && (node.Host is DynamicParser.Node.Argument || node.Host is DynamicParser.Node.Invoke))
{
if (type != null) throw new ArgumentException(string.Format("Join type '{0}' is already set when parsing '{1}'.", main, result));
type = ((DynamicParser.Node.Method)node).Name;

View File

@@ -35,6 +35,7 @@
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<DebugSymbols>true</DebugSymbols>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DocumentationFile>bin\Release\DynamORM.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />

View File

@@ -652,39 +652,41 @@ namespace DynamORM
if (connection == null)
return;
lock (SyncLock)
if (!_singleConnection && connection != null && TransactionPool.ContainsKey(connection))
{
if (!_singleConnection && connection != null && TransactionPool.ContainsKey(connection))
// Close all commands
if (CommandsPool.ContainsKey(connection))
{
// Close all commands
if (CommandsPool.ContainsKey(connection))
{
CommandsPool[connection].ForEach(cmd => cmd.Dispose());
CommandsPool[connection].Clear();
}
var tmp = CommandsPool[connection].ToList();
tmp.ForEach(cmd => cmd.Dispose());
// Rollback remaining transactions
while (TransactionPool[connection].Count > 0)
{
IDbTransaction trans = TransactionPool[connection].Pop();
trans.Rollback();
trans.Dispose();
}
CommandsPool[connection].Clear();
}
// Close connection
if (connection.State == ConnectionState.Open)
connection.Close();
// Rollback remaining transactions
while (TransactionPool[connection].Count > 0)
{
IDbTransaction trans = TransactionPool[connection].Pop();
trans.Rollback();
trans.Dispose();
}
// remove from pools
// Close connection
if (connection.State == ConnectionState.Open)
connection.Close();
// remove from pools
lock (SyncLock)
{
TransactionPool.Remove(connection);
CommandsPool.Remove(connection);
// Set stamp
_poolStamp = DateTime.Now.Ticks;
// Dispose the corpse
connection.Dispose();
}
// Set stamp
_poolStamp = DateTime.Now.Ticks;
// Dispose the corpse
connection.Dispose();
}
}
@@ -733,43 +735,46 @@ namespace DynamORM
/// releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
lock (SyncLock)
var tables = TablesCache.Values.ToList();
TablesCache.Clear();
tables.ForEach(t => t.Dispose());
foreach (var con in TransactionPool)
{
var tables = TablesCache.Values.ToList();
TablesCache.Clear();
tables.ForEach(t => t.Dispose());
foreach (var con in TransactionPool)
// Close all commands
if (CommandsPool.ContainsKey(con.Key))
{
// Close all commands
if (CommandsPool.ContainsKey(con.Key))
{
CommandsPool[con.Key].ForEach(cmd => cmd.Dispose());
CommandsPool[con.Key].Clear();
}
var tmp = CommandsPool[con.Key].ToList();
tmp.ForEach(cmd => cmd.Dispose());
// Rollback remaining transactions
while (con.Value.Count > 0)
{
IDbTransaction trans = con.Value.Pop();
trans.Rollback();
trans.Dispose();
}
// Close connection
if (con.Key.State == ConnectionState.Open)
con.Key.Close();
// Dispose it
con.Key.Dispose();
CommandsPool[con.Key].Clear();
}
// Clear pools
// Rollback remaining transactions
while (con.Value.Count > 0)
{
IDbTransaction trans = con.Value.Pop();
trans.Rollback();
trans.Dispose();
}
// Close connection
if (con.Key.State == ConnectionState.Open)
con.Key.Close();
// Dispose it
con.Key.Dispose();
}
// Clear pools
lock (SyncLock)
{
TransactionPool.Clear();
CommandsPool.Clear();
IsDisposed = true;
}
IsDisposed = true;
}
/// <summary>Gets a value indicating whether this instance is disposed.</summary>

View File

@@ -816,6 +816,17 @@ namespace DynamORM
return b;
}
/// <summary>Sets the virtual mode on builder.</summary>
/// <typeparam name="T">Class implementing <see cref="IDynamicQueryBuilder"/> interface.</typeparam>
/// <param name="b">The builder on which set delegate.</param>
/// <param name="virtualMode">Virtual mode.</param>
/// <returns>Returns instance of builder on which virtual mode is set.</returns>
public static T SetVirtualMode<T>(this T b, bool virtualMode) where T : IDynamicQueryBuilder
{
b.VirtualMode = virtualMode;
return b;
}
/// <summary>Sets the on create real parameter action.</summary>
/// <typeparam name="T">Class implementing <see cref="IDynamicQueryBuilder"/> interface.</typeparam>
/// <param name="b">The builder on which set delegate.</param>
@@ -1071,7 +1082,7 @@ namespace DynamORM
{
TValue val;
if (dict.TryGetValue(key, out val))
if (key != null && dict.TryGetValue(key, out val))
return val;
return null;
@@ -1087,7 +1098,7 @@ namespace DynamORM
{
TValue val;
if (dict.TryGetValue(key, out val))
if (key != null && dict.TryGetValue(key, out val))
return val;
return default(TValue);

View File

@@ -696,7 +696,7 @@ namespace DynamORM.Helpers.Dynamics
/// <summary>
/// Represents a binary operation between a dynamic element and an arbitrary object, including null ones, as in
/// 'x =&gt; (x &amp;&amp; null)'. The left operand must be an instance of <see cref="DynamicNode"/>, whereas the right one
/// 'x =&gt; (x &amp;&amp; null)'. The left operand must be an instance of <see cref="Node"/>, whereas the right one
/// can be any object, including null values.
/// </summary>
[Serializable]
@@ -770,7 +770,7 @@ namespace DynamORM.Helpers.Dynamics
#region Unary
/// <summary>
/// Represents an unary operation, as in 'x => !x'. The target must be a <see cref="DynamicNode"/> instance. There
/// Represents an unary operation, as in 'x => !x'. The target must be a <see cref="Node"/> instance. There
/// is no distinction between pre- and post- version of the same operation.
/// </summary>
[Serializable]
@@ -1055,7 +1055,7 @@ namespace DynamORM.Helpers.Dynamics
/// <summary>
/// Gets the result of the parsing of the dynamic lambda expression. This result can be either an arbitrary object,
/// including null, if the expression resolves to it, or an instance of the <see cref="DynamicNode"/> class that
/// including null, if the expression resolves to it, or an instance of the <see cref="Node"/> class that
/// contains the last logic expression evaluated when parsing the dynamic lambda expression.
/// </summary>
public object Result

View File

@@ -205,7 +205,7 @@ namespace DynamORM.Helpers.Dynamics
/// during the invoke operation. For example, for the statement
/// sampleObject.SampleMethod(100), where sampleObject is derived from the
/// <see cref="T:System.Dynamic.DynamicObject" /> class,
/// <paramref name="args[0]" /> is equal to 100.</param>
/// First element of <paramref name="args" /> is equal to 100.</param>
/// <param name="result">The result of the member invocation.</param>
/// <returns>Returns <c>true</c> if the operation is successful; otherwise,
/// <c>false</c>. If this method returns false, the run-time binder of the

View File

@@ -58,7 +58,7 @@ namespace DynamORM.Helpers
/// <summary>
/// Provides with an alternate and generic way to obtain an alternate string representation for this instance,
/// applying the following rules:
/// <para>- Null values are returned as with the <see cref="NullString"/> value, or a null object.</para>
/// <para>- Null values are returned as with the <paramref name="nullString"/> value, or a null object.</para>
/// <para>- Enum values are translated into their string representation.</para>
/// <para>- If the type has override the 'ToString' method then it is used.</para>
/// <para>- If it is a dictionary, then a collection of key/value pairs where the value part is also translated.</para>