This commit is contained in:
grzegorz.russek
2016-02-04 08:52:44 +00:00
parent 9e40c4e20b
commit f5b4834fd5
5 changed files with 1350 additions and 1174 deletions

View File

@@ -33,31 +33,31 @@
* * DYNAMORM_OMMIT_TRYPARSE - Remove TryParse helpers (also applies DYNAMORM_OMMIT_GENERICEXECUTION) * * DYNAMORM_OMMIT_TRYPARSE - Remove TryParse helpers (also applies DYNAMORM_OMMIT_GENERICEXECUTION)
*/ */
using System; using DynamORM.Builders.Extensions;
using System.Collections; using DynamORM.Builders.Implementation;
using DynamORM.Builders;
using DynamORM.Helpers.Dynamics;
using DynamORM.Helpers;
using DynamORM.Mapper;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Data; using System.Collections;
using System.Data.Common; using System.Data.Common;
using System.Data;
using System.Dynamic; using System.Dynamic;
using System.IO; using System.IO;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
using DynamORM.Builders; using System;
using DynamORM.Builders.Extensions;
using DynamORM.Builders.Implementation;
using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "This is a generated file which generates all the necessary support classes.")] [module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "This is a generated file which generates all the necessary support classes.")]
[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1403:FileMayOnlyContainASingleNamespace", Justification = "This is a generated file which generates all the necessary support classes.")] [module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1403:FileMayOnlyContainASingleNamespace", Justification = "This is a generated file which generates all the necessary support classes.")]
namespace DynamORM namespace DynamORM
{ {
/// <summary>Small utility class to manage single columns.</summary> /// <summary>Small utility class to manage single columns.</summary>
@@ -2687,11 +2687,14 @@ namespace DynamORM
/// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary> /// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary>
SupportLimitOffset = 0x00000040, SupportLimitOffset = 0x00000040,
/// <summary>Database supports limit offset syntax (SELECT FIRST x SKIP y ... FROM ...).</summary>
SupportFirstSkip = 0x00000020,
/// <summary>Database support standard schema.</summary> /// <summary>Database support standard schema.</summary>
SupportSchema = 0x00000010, SupportSchema = 0x00000010,
/// <summary>Database support stored procedures (EXEC procedure ...).</summary> /// <summary>Database support stored procedures (EXEC procedure ...).</summary>
SupportStoredProcedures = 0x00000020, SupportStoredProcedures = 0x00000100,
/// <summary>Debug option allowing to enable command dumps by default.</summary> /// <summary>Debug option allowing to enable command dumps by default.</summary>
DumpCommands = 0x01000000, DumpCommands = 0x01000000,
@@ -4101,7 +4104,7 @@ namespace DynamORM
/// <returns>Returns <c>true</c> if it does.</returns> /// <returns>Returns <c>true</c> if it does.</returns>
public static bool IsGenericEnumerable(this Type type) public static bool IsGenericEnumerable(this Type type)
{ {
return type.IsGenericType && type.GetInterfaces().Any(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>)); return type.IsGenericType && type.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
} }
/// <summary>Check if type implements IEnumerable&lt;&gt; interface.</summary> /// <summary>Check if type implements IEnumerable&lt;&gt; interface.</summary>
@@ -5854,6 +5857,7 @@ namespace DynamORM
IDynamicDeleteQueryBuilder Where(object conditions, bool schema = false); IDynamicDeleteQueryBuilder Where(object conditions, bool schema = false);
} }
/// <summary>Dynamic insert query builder interface.</summary> /// <summary>Dynamic insert query builder interface.</summary>
/// <remarks>This interface it publically available. Implementation should be hidden.</remarks> /// <remarks>This interface it publically available. Implementation should be hidden.</remarks>
public interface IDynamicInsertQueryBuilder : IDynamicQueryBuilder public interface IDynamicInsertQueryBuilder : IDynamicQueryBuilder
@@ -5885,6 +5889,7 @@ namespace DynamORM
IDynamicInsertQueryBuilder Insert(object o); IDynamicInsertQueryBuilder Insert(object o);
} }
/// <summary>Dynamic query builder base interface.</summary> /// <summary>Dynamic query builder base interface.</summary>
/// <remarks>This interface it publically available. Implementation should be hidden.</remarks> /// <remarks>This interface it publically available. Implementation should be hidden.</remarks>
public interface IDynamicQueryBuilder : IExtendedDisposable public interface IDynamicQueryBuilder : IExtendedDisposable
@@ -5925,6 +5930,7 @@ namespace DynamORM
List<Action<IParameter, IDbDataParameter>> OnCreateParameter { get; set; } List<Action<IParameter, IDbDataParameter>> OnCreateParameter { get; set; }
} }
/// <summary>Dynamic select query builder interface.</summary> /// <summary>Dynamic select query builder interface.</summary>
/// <remarks>This interface it publically available. Implementation should be hidden.</remarks> /// <remarks>This interface it publically available. Implementation should be hidden.</remarks>
public interface IDynamicSelectQueryBuilder : IDynamicQueryBuilder ////, IEnumerable<object> public interface IDynamicSelectQueryBuilder : IDynamicQueryBuilder ////, IEnumerable<object>
@@ -5946,7 +5952,7 @@ namespace DynamORM
/// <returns>Result of a query.</returns> /// <returns>Result of a query.</returns>
object Scalar(); object Scalar();
#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE #if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE
/// <summary>Returns a single result.</summary> /// <summary>Returns a single result.</summary>
/// <typeparam name="T">Type to parse to.</typeparam> /// <typeparam name="T">Type to parse to.</typeparam>
@@ -5954,7 +5960,7 @@ namespace DynamORM
/// <returns>Result of a query.</returns> /// <returns>Result of a query.</returns>
T ScalarAs<T>(T defaultValue = default(T)); T ScalarAs<T>(T defaultValue = default(T));
#endif #endif
#region From/Join #region From/Join
@@ -6138,6 +6144,7 @@ namespace DynamORM
#endregion Top/Limit/Offset/Distinct #endregion Top/Limit/Offset/Distinct
} }
/// <summary>Dynamic update query builder interface.</summary> /// <summary>Dynamic update query builder interface.</summary>
/// <remarks>This interface it publically available. Implementation should be hidden.</remarks> /// <remarks>This interface it publically available. Implementation should be hidden.</remarks>
public interface IDynamicUpdateQueryBuilder : IDynamicQueryBuilder public interface IDynamicUpdateQueryBuilder : IDynamicQueryBuilder
@@ -6228,6 +6235,7 @@ namespace DynamORM
#endregion Where #endregion Where
} }
/// <summary>Interface describing parameter info.</summary> /// <summary>Interface describing parameter info.</summary>
public interface IParameter : IExtendedDisposable public interface IParameter : IExtendedDisposable
{ {
@@ -6251,6 +6259,7 @@ namespace DynamORM
DynamicSchemaColumn? Schema { get; set; } DynamicSchemaColumn? Schema { get; set; }
} }
/// <summary>Interface describing table information.</summary> /// <summary>Interface describing table information.</summary>
public interface ITableInfo : IExtendedDisposable public interface ITableInfo : IExtendedDisposable
{ {
@@ -6267,6 +6276,7 @@ namespace DynamORM
Dictionary<string, DynamicSchemaColumn> Schema { get; } Dictionary<string, DynamicSchemaColumn> Schema { get; }
} }
namespace Extensions namespace Extensions
{ {
internal static class DynamicModifyBuilderExtensions internal static class DynamicModifyBuilderExtensions
@@ -6390,6 +6400,7 @@ namespace DynamORM
} }
} }
internal static class DynamicWhereQueryExtensions internal static class DynamicWhereQueryExtensions
{ {
#region Where #region Where
@@ -6594,6 +6605,8 @@ namespace DynamORM
#endregion Where #endregion Where
} }
} }
namespace Implementation namespace Implementation
@@ -6690,6 +6703,7 @@ namespace DynamORM
#endregion Where #endregion Where
} }
/// <summary>Implementation of dynamic insert query builder.</summary> /// <summary>Implementation of dynamic insert query builder.</summary>
internal class DynamicInsertQueryBuilder : DynamicModifyBuilder, IDynamicInsertQueryBuilder internal class DynamicInsertQueryBuilder : DynamicModifyBuilder, IDynamicInsertQueryBuilder
{ {
@@ -6875,6 +6889,7 @@ namespace DynamORM
#endregion IExtendedDisposable #endregion IExtendedDisposable
} }
/// <summary>Base query builder for insert/update/delete statements.</summary> /// <summary>Base query builder for insert/update/delete statements.</summary>
internal abstract class DynamicModifyBuilder : DynamicQueryBuilder internal abstract class DynamicModifyBuilder : DynamicQueryBuilder
{ {
@@ -6914,6 +6929,7 @@ namespace DynamORM
} }
} }
/// <summary>Implementation of dynamic query builder base interface.</summary> /// <summary>Implementation of dynamic query builder base interface.</summary>
internal abstract class DynamicQueryBuilder : IDynamicQueryBuilder internal abstract class DynamicQueryBuilder : IDynamicQueryBuilder
{ {
@@ -7813,10 +7829,10 @@ namespace DynamORM
#endregion IExtendedDisposable #endregion IExtendedDisposable
} }
/// <summary>Implementation of dynamic select query builder.</summary> /// <summary>Implementation of dynamic select query builder.</summary>
internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, DynamicQueryBuilder.IQueryWithWhere internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{ {
private int? _top = null;
private int? _limit = null; private int? _limit = null;
private int? _offset = null; private int? _offset = null;
private bool _distinct = false; private bool _distinct = false;
@@ -7855,17 +7871,42 @@ namespace DynamORM
/// <returns>The text to execute against the underlying database.</returns> /// <returns>The text to execute against the underlying database.</returns>
public override string CommandText() public override string CommandText()
{ {
bool lused = false;
bool oused = false;
StringBuilder sb = new StringBuilder("SELECT"); StringBuilder sb = new StringBuilder("SELECT");
if (_distinct) sb.AppendFormat(" DISTINCT"); if (_distinct) sb.AppendFormat(" DISTINCT");
if (_top.HasValue) sb.AppendFormat(" TOP {0}", _top);
if (_limit.HasValue)
{
if ((Database.Options & DynamicDatabaseOptions.SupportTop) == DynamicDatabaseOptions.SupportTop)
{
sb.AppendFormat(" TOP {0}", _limit);
lused = true;
}
else if ((Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == DynamicDatabaseOptions.SupportFirstSkip)
{
sb.AppendFormat(" FIRST {0}", _limit);
lused = true;
}
}
if (_offset.HasValue && (Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == DynamicDatabaseOptions.SupportFirstSkip)
{
sb.AppendFormat(" SKIP {0}", _offset);
oused = true;
}
if (_select != null) sb.AppendFormat(" {0}", _select); else sb.Append(" *"); if (_select != null) sb.AppendFormat(" {0}", _select); else sb.Append(" *");
if (_from != null) sb.AppendFormat(" FROM {0}", _from); if (_from != null) sb.AppendFormat(" FROM {0}", _from);
if (_join != null) sb.AppendFormat(" {0}", _join); if (_join != null) sb.AppendFormat(" {0}", _join);
if (WhereCondition != null) sb.AppendFormat(" WHERE {0}", WhereCondition); if (WhereCondition != null) sb.AppendFormat(" WHERE {0}", WhereCondition);
if (_groupby != null) sb.AppendFormat(" GROUP BY {0}", _groupby); if (_groupby != null) sb.AppendFormat(" GROUP BY {0}", _groupby);
if (_orderby != null) sb.AppendFormat(" ORDER BY {0}", _orderby); if (_orderby != null) sb.AppendFormat(" ORDER BY {0}", _orderby);
if (_limit.HasValue) sb.AppendFormat(" LIMIT {0}", _limit); if (_limit.HasValue && !lused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
if (_offset.HasValue) sb.AppendFormat(" OFFSET {0}", _offset); sb.AppendFormat(" LIMIT {0}", _limit);
if (_offset.HasValue && !oused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
sb.AppendFormat(" OFFSET {0}", _offset);
return sb.ToString(); return sb.ToString();
} }
@@ -7969,7 +8010,7 @@ namespace DynamORM
} }
} }
#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE #if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE
/// <summary>Returns a single result.</summary> /// <summary>Returns a single result.</summary>
/// <typeparam name="T">Type to parse to.</typeparam> /// <typeparam name="T">Type to parse to.</typeparam>
@@ -7986,7 +8027,7 @@ namespace DynamORM
} }
} }
#endif #endif
#endregion Execution #endregion Execution
@@ -8877,11 +8918,7 @@ namespace DynamORM
/// <returns>Builder instance.</returns> /// <returns>Builder instance.</returns>
public virtual IDynamicSelectQueryBuilder Top(int? top) public virtual IDynamicSelectQueryBuilder Top(int? top)
{ {
if ((Database.Options & DynamicDatabaseOptions.SupportTop) != DynamicDatabaseOptions.SupportTop) return Limit(top);
throw new NotSupportedException("Database doesn't support TOP clause.");
_top = top;
return this;
} }
/// <summary>Set top if database support it.</summary> /// <summary>Set top if database support it.</summary>
@@ -8889,7 +8926,9 @@ namespace DynamORM
/// <returns>Builder instance.</returns> /// <returns>Builder instance.</returns>
public virtual IDynamicSelectQueryBuilder Limit(int? limit) public virtual IDynamicSelectQueryBuilder Limit(int? limit)
{ {
if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset) if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset &&
(Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != DynamicDatabaseOptions.SupportFirstSkip &&
(Database.Options & DynamicDatabaseOptions.SupportTop) != DynamicDatabaseOptions.SupportTop)
throw new NotSupportedException("Database doesn't support LIMIT clause."); throw new NotSupportedException("Database doesn't support LIMIT clause.");
_limit = limit; _limit = limit;
@@ -8901,7 +8940,8 @@ namespace DynamORM
/// <returns>Builder instance.</returns> /// <returns>Builder instance.</returns>
public virtual IDynamicSelectQueryBuilder Offset(int? offset) public virtual IDynamicSelectQueryBuilder Offset(int? offset)
{ {
if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset) if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset &&
(Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != DynamicDatabaseOptions.SupportFirstSkip)
throw new NotSupportedException("Database doesn't support OFFSET clause."); throw new NotSupportedException("Database doesn't support OFFSET clause.");
_offset = offset; _offset = offset;
@@ -9078,6 +9118,7 @@ namespace DynamORM
#endregion IExtendedDisposable #endregion IExtendedDisposable
} }
/// <summary>Update query builder.</summary> /// <summary>Update query builder.</summary>
internal class DynamicUpdateQueryBuilder : DynamicModifyBuilder, IDynamicUpdateQueryBuilder, DynamicQueryBuilder.IQueryWithWhere internal class DynamicUpdateQueryBuilder : DynamicModifyBuilder, IDynamicUpdateQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{ {
@@ -9377,7 +9418,10 @@ namespace DynamORM
#endregion IExtendedDisposable #endregion IExtendedDisposable
} }
} }
} }
namespace Helpers namespace Helpers
@@ -9475,6 +9519,7 @@ namespace DynamORM
} }
} }
/// <summary>Framework detection and specific implementations.</summary> /// <summary>Framework detection and specific implementations.</summary>
public static class FrameworkTools public static class FrameworkTools
{ {
@@ -9595,6 +9640,7 @@ namespace DynamORM
#endregion GetGenericTypeArguments #endregion GetGenericTypeArguments
} }
/// <summary>Extends <see cref="IDisposable"/> interface.</summary> /// <summary>Extends <see cref="IDisposable"/> interface.</summary>
public interface IExtendedDisposable : IDisposable public interface IExtendedDisposable : IDisposable
{ {
@@ -9607,6 +9653,7 @@ namespace DynamORM
bool IsDisposed { get; } bool IsDisposed { get; }
} }
/// <summary>Extends <see cref="IExtendedDisposable"/> interface.</summary> /// <summary>Extends <see cref="IExtendedDisposable"/> interface.</summary>
public interface IFinalizerDisposable : IExtendedDisposable public interface IFinalizerDisposable : IExtendedDisposable
{ {
@@ -9616,6 +9663,7 @@ namespace DynamORM
void Dispose(bool disposing); void Dispose(bool disposing);
} }
/// <summary>Class containing useful string extensions.</summary> /// <summary>Class containing useful string extensions.</summary>
internal static class StringExtensions internal static class StringExtensions
{ {
@@ -9913,6 +9961,7 @@ namespace DynamORM
} }
} }
/// <summary>Class contains unclassified extensions.</summary> /// <summary>Class contains unclassified extensions.</summary>
internal static class UnclassifiedExtensions internal static class UnclassifiedExtensions
{ {
@@ -9970,6 +10019,7 @@ namespace DynamORM
} }
} }
namespace Dynamics namespace Dynamics
{ {
/// <summary> /// <summary>
@@ -11167,6 +11217,7 @@ namespace DynamORM
#endregion Implementation of IExtendedDisposable #endregion Implementation of IExtendedDisposable
} }
/// <summary>Class that allows to use interfaces as dynamic objects.</summary> /// <summary>Class that allows to use interfaces as dynamic objects.</summary>
/// <typeparam name="T">Type of class to proxy.</typeparam> /// <typeparam name="T">Type of class to proxy.</typeparam>
/// <remarks>This is temporary solution. Which allows to use builders as a dynamic type.</remarks> /// <remarks>This is temporary solution. Which allows to use builders as a dynamic type.</remarks>
@@ -11459,7 +11510,10 @@ namespace DynamORM
_proxy = default(T); _proxy = default(T);
} }
} }
} }
} }
namespace Mapper namespace Mapper
@@ -11605,6 +11659,7 @@ namespace DynamORM
#endregion Constructors #endregion Constructors
} }
/// <summary>Type cast helper.</summary> /// <summary>Type cast helper.</summary>
public static class DynamicCast public static class DynamicCast
{ {
@@ -11690,6 +11745,7 @@ namespace DynamORM
} }
} }
/// <summary>Class with mapper cache.</summary> /// <summary>Class with mapper cache.</summary>
public static class DynamicMapperCache public static class DynamicMapperCache
{ {
@@ -11731,6 +11787,7 @@ namespace DynamORM
} }
} }
/// <summary>Dynamic property invoker.</summary> /// <summary>Dynamic property invoker.</summary>
public class DynamicPropertyInvoker public class DynamicPropertyInvoker
{ {
@@ -11743,6 +11800,9 @@ namespace DynamORM
public int Ordinal { get; set; } public int Ordinal { get; set; }
} }
private Type _arrayType;
private bool _genericEnumerable;
/// <summary>Gets the type of property.</summary> /// <summary>Gets the type of property.</summary>
public Type Type { get; private set; } public Type Type { get; private set; }
@@ -11761,6 +11821,9 @@ namespace DynamORM
/// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary> /// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary>
public bool Ignore { get; private set; } public bool Ignore { get; private set; }
/// <summary>Gets a value indicating whether this instance hold data contract type.</summary>
public bool IsDataContract { get; private set; }
/// <summary>Initializes a new instance of the <see cref="DynamicPropertyInvoker" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="DynamicPropertyInvoker" /> class.</summary>
/// <param name="property">Property info to be invoked in the future.</param> /// <param name="property">Property info to be invoked in the future.</param>
/// <param name="attr">Column attribute if exist.</param> /// <param name="attr">Column attribute if exist.</param>
@@ -11773,6 +11836,20 @@ namespace DynamORM
Ignore = ignore != null && ignore.Length > 0; Ignore = ignore != null && ignore.Length > 0;
_arrayType = Type.IsArray ? Type.GetElementType() :
Type.IsGenericEnumerable() ? Type.GetGenericArguments().First() :
Type;
_genericEnumerable = Type.IsGenericEnumerable();
IsDataContract = _arrayType.GetCustomAttributes(false).Any(x => x.GetType().Name == "DataContractAttribute");
if (_arrayType.IsArray)
throw new InvalidOperationException("Jagged arrays are not supported");
if (_arrayType.IsGenericEnumerable())
throw new InvalidOperationException("Enumerables of enumerables are not supported");
Column = attr; Column = attr;
if (property.CanRead) if (property.CanRead)
@@ -11819,43 +11896,65 @@ namespace DynamORM
/// <param name="val">The value.</param> /// <param name="val">The value.</param>
public void Set(object dest, object val) public void Set(object dest, object val)
{ {
Type type = Nullable.GetUnderlyingType(Type) ?? Type; object value = null;
bool nullable = Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>);
try try
{ {
if (val == null && type.IsValueType) if (Type.IsArray || _genericEnumerable)
{ {
if (nullable) var lst = (val as IEnumerable<object>).Select(x => GetElementVal(_arrayType, x)).ToList();
Setter(dest, null);
else value = Array.CreateInstance(_arrayType, lst.Count);
Setter(dest, Activator.CreateInstance(Type));
} int i = 0;
else if ((val == null && !type.IsValueType) || (val != null && type == val.GetType())) foreach (var e in lst)
Setter(dest, val); ((Array)value).SetValue(e, i++);
else if (type.IsEnum && val.GetType().IsValueType)
Setter(dest, Enum.ToObject(type, val));
else if (type.IsEnum)
Setter(dest, Enum.Parse(type, val.ToString()));
else if (Type == typeof(string) && val.GetType() == typeof(Guid))
Setter(dest, val.ToString());
else if (Type == typeof(Guid) && val.GetType() == typeof(string))
{
Guid g;
Setter(dest, Guid.TryParse((string)val, out g) ? g : Guid.Empty);
} }
else else
Setter(dest, Convert.ChangeType(val, type)); value = GetElementVal(Type, val);
Setter(dest, value);
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new InvalidCastException( throw new InvalidCastException(
string.Format("Error trying to convert value '{0}' of type '{1}' to value of type '{2}{3}' in object of type '{4}'", string.Format("Error trying to convert value '{0}' of type '{1}' to value of type '{2}' in object of type '{3}'",
val.ToString(), val.GetType(), type.FullName, nullable ? "(NULLABLE)" : string.Empty, dest.GetType().FullName), (val ?? string.Empty).ToString(), val.GetType(), Type.FullName, dest.GetType().FullName),
ex); ex);
} }
} }
private object GetElementVal(System.Type etype, object val)
{
bool nullable = etype.IsGenericType && etype.GetGenericTypeDefinition() == typeof(Nullable<>);
Type type = Nullable.GetUnderlyingType(etype) ?? etype;
if (val == null && type.IsValueType)
{
if (nullable)
return null;
else
return Activator.CreateInstance(Type);
}
else if ((val == null && !type.IsValueType) || (val != null && type == val.GetType()))
return val;
else if (type.IsEnum && val.GetType().IsValueType)
return Enum.ToObject(type, val);
else if (type.IsEnum)
return Enum.Parse(type, val.ToString());
else if (Type == typeof(string) && val.GetType() == typeof(Guid))
return val.ToString();
else if (Type == typeof(Guid) && val.GetType() == typeof(string))
{
Guid g;
return Guid.TryParse((string)val, out g) ? g : Guid.Empty;
}
else if (IsDataContract)
return val.Map(type);
else
return Convert.ChangeType(val, type);
}
#region Type command cache #region Type command cache
internal ParameterSpec InsertCommandParameter { get; set; } internal ParameterSpec InsertCommandParameter { get; set; }
@@ -11867,6 +11966,7 @@ namespace DynamORM
#endregion Type command cache #endregion Type command cache
} }
/// <summary>Represents type columnMap.</summary> /// <summary>Represents type columnMap.</summary>
public class DynamicTypeMap public class DynamicTypeMap
{ {
@@ -12021,6 +12121,7 @@ namespace DynamORM
#endregion Type command cache #endregion Type command cache
} }
/// <summary>Allows to add ignore action to property.</summary> /// <summary>Allows to add ignore action to property.</summary>
/// <remarks>Property still get's mapped from output.</remarks> /// <remarks>Property still get's mapped from output.</remarks>
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
@@ -12028,6 +12129,7 @@ namespace DynamORM
{ {
} }
/// <summary>Allows to add table name to class.</summary> /// <summary>Allows to add table name to class.</summary>
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute public class TableAttribute : Attribute
@@ -12044,5 +12146,9 @@ namespace DynamORM
/// set this to true to get schema from type.</remarks> /// set this to true to get schema from type.</remarks>
public bool Override { get; set; } public bool Override { get; set; }
} }
} }
} }

View File

@@ -44,7 +44,6 @@ namespace DynamORM.Builders.Implementation
/// <summary>Implementation of dynamic select query builder.</summary> /// <summary>Implementation of dynamic select query builder.</summary>
internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, DynamicQueryBuilder.IQueryWithWhere internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
{ {
private int? _top = null;
private int? _limit = null; private int? _limit = null;
private int? _offset = null; private int? _offset = null;
private bool _distinct = false; private bool _distinct = false;
@@ -83,17 +82,42 @@ namespace DynamORM.Builders.Implementation
/// <returns>The text to execute against the underlying database.</returns> /// <returns>The text to execute against the underlying database.</returns>
public override string CommandText() public override string CommandText()
{ {
bool lused = false;
bool oused = false;
StringBuilder sb = new StringBuilder("SELECT"); StringBuilder sb = new StringBuilder("SELECT");
if (_distinct) sb.AppendFormat(" DISTINCT"); if (_distinct) sb.AppendFormat(" DISTINCT");
if (_top.HasValue) sb.AppendFormat(" TOP {0}", _top);
if (_limit.HasValue)
{
if ((Database.Options & DynamicDatabaseOptions.SupportTop) == DynamicDatabaseOptions.SupportTop)
{
sb.AppendFormat(" TOP {0}", _limit);
lused = true;
}
else if ((Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == DynamicDatabaseOptions.SupportFirstSkip)
{
sb.AppendFormat(" FIRST {0}", _limit);
lused = true;
}
}
if (_offset.HasValue && (Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == DynamicDatabaseOptions.SupportFirstSkip)
{
sb.AppendFormat(" SKIP {0}", _offset);
oused = true;
}
if (_select != null) sb.AppendFormat(" {0}", _select); else sb.Append(" *"); if (_select != null) sb.AppendFormat(" {0}", _select); else sb.Append(" *");
if (_from != null) sb.AppendFormat(" FROM {0}", _from); if (_from != null) sb.AppendFormat(" FROM {0}", _from);
if (_join != null) sb.AppendFormat(" {0}", _join); if (_join != null) sb.AppendFormat(" {0}", _join);
if (WhereCondition != null) sb.AppendFormat(" WHERE {0}", WhereCondition); if (WhereCondition != null) sb.AppendFormat(" WHERE {0}", WhereCondition);
if (_groupby != null) sb.AppendFormat(" GROUP BY {0}", _groupby); if (_groupby != null) sb.AppendFormat(" GROUP BY {0}", _groupby);
if (_orderby != null) sb.AppendFormat(" ORDER BY {0}", _orderby); if (_orderby != null) sb.AppendFormat(" ORDER BY {0}", _orderby);
if (_limit.HasValue) sb.AppendFormat(" LIMIT {0}", _limit); if (_limit.HasValue && !lused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
if (_offset.HasValue) sb.AppendFormat(" OFFSET {0}", _offset); sb.AppendFormat(" LIMIT {0}", _limit);
if (_offset.HasValue && !oused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
sb.AppendFormat(" OFFSET {0}", _offset);
return sb.ToString(); return sb.ToString();
} }
@@ -1105,11 +1129,7 @@ namespace DynamORM.Builders.Implementation
/// <returns>Builder instance.</returns> /// <returns>Builder instance.</returns>
public virtual IDynamicSelectQueryBuilder Top(int? top) public virtual IDynamicSelectQueryBuilder Top(int? top)
{ {
if ((Database.Options & DynamicDatabaseOptions.SupportTop) != DynamicDatabaseOptions.SupportTop) return Limit(top);
throw new NotSupportedException("Database doesn't support TOP clause.");
_top = top;
return this;
} }
/// <summary>Set top if database support it.</summary> /// <summary>Set top if database support it.</summary>
@@ -1117,7 +1137,9 @@ namespace DynamORM.Builders.Implementation
/// <returns>Builder instance.</returns> /// <returns>Builder instance.</returns>
public virtual IDynamicSelectQueryBuilder Limit(int? limit) public virtual IDynamicSelectQueryBuilder Limit(int? limit)
{ {
if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset) if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset &&
(Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != DynamicDatabaseOptions.SupportFirstSkip &&
(Database.Options & DynamicDatabaseOptions.SupportTop) != DynamicDatabaseOptions.SupportTop)
throw new NotSupportedException("Database doesn't support LIMIT clause."); throw new NotSupportedException("Database doesn't support LIMIT clause.");
_limit = limit; _limit = limit;
@@ -1129,7 +1151,8 @@ namespace DynamORM.Builders.Implementation
/// <returns>Builder instance.</returns> /// <returns>Builder instance.</returns>
public virtual IDynamicSelectQueryBuilder Offset(int? offset) public virtual IDynamicSelectQueryBuilder Offset(int? offset)
{ {
if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset) if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset &&
(Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != DynamicDatabaseOptions.SupportFirstSkip)
throw new NotSupportedException("Database doesn't support OFFSET clause."); throw new NotSupportedException("Database doesn't support OFFSET clause.");
_offset = offset; _offset = offset;

View File

@@ -50,11 +50,14 @@ namespace DynamORM
/// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary> /// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary>
SupportLimitOffset = 0x00000040, SupportLimitOffset = 0x00000040,
/// <summary>Database supports limit offset syntax (SELECT FIRST x SKIP y ... FROM ...).</summary>
SupportFirstSkip = 0x00000020,
/// <summary>Database support standard schema.</summary> /// <summary>Database support standard schema.</summary>
SupportSchema = 0x00000010, SupportSchema = 0x00000010,
/// <summary>Database support stored procedures (EXEC procedure ...).</summary> /// <summary>Database support stored procedures (EXEC procedure ...).</summary>
SupportStoredProcedures = 0x00000020, SupportStoredProcedures = 0x00000100,
/// <summary>Debug option allowing to enable command dumps by default.</summary> /// <summary>Debug option allowing to enable command dumps by default.</summary>
DumpCommands = 0x01000000, DumpCommands = 0x01000000,

View File

@@ -1283,7 +1283,7 @@ namespace DynamORM
/// <returns>Returns <c>true</c> if it does.</returns> /// <returns>Returns <c>true</c> if it does.</returns>
public static bool IsGenericEnumerable(this Type type) public static bool IsGenericEnumerable(this Type type)
{ {
return type.IsGenericType && type.GetInterfaces().Any(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>)); return type.IsGenericType && type.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
} }
/// <summary>Check if type implements IEnumerable&lt;&gt; interface.</summary> /// <summary>Check if type implements IEnumerable&lt;&gt; interface.</summary>

View File

@@ -27,7 +27,9 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
@@ -45,6 +47,9 @@ namespace DynamORM.Mapper
public int Ordinal { get; set; } public int Ordinal { get; set; }
} }
private Type _arrayType;
private bool _genericEnumerable;
/// <summary>Gets the type of property.</summary> /// <summary>Gets the type of property.</summary>
public Type Type { get; private set; } public Type Type { get; private set; }
@@ -63,6 +68,9 @@ namespace DynamORM.Mapper
/// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary> /// <summary>Gets a value indicating whether this <see cref="DynamicPropertyInvoker"/> is ignored in some cases.</summary>
public bool Ignore { get; private set; } public bool Ignore { get; private set; }
/// <summary>Gets a value indicating whether this instance hold data contract type.</summary>
public bool IsDataContract { get; private set; }
/// <summary>Initializes a new instance of the <see cref="DynamicPropertyInvoker" /> class.</summary> /// <summary>Initializes a new instance of the <see cref="DynamicPropertyInvoker" /> class.</summary>
/// <param name="property">Property info to be invoked in the future.</param> /// <param name="property">Property info to be invoked in the future.</param>
/// <param name="attr">Column attribute if exist.</param> /// <param name="attr">Column attribute if exist.</param>
@@ -75,6 +83,20 @@ namespace DynamORM.Mapper
Ignore = ignore != null && ignore.Length > 0; Ignore = ignore != null && ignore.Length > 0;
_arrayType = Type.IsArray ? Type.GetElementType() :
Type.IsGenericEnumerable() ? Type.GetGenericArguments().First() :
Type;
_genericEnumerable = Type.IsGenericEnumerable();
IsDataContract = _arrayType.GetCustomAttributes(false).Any(x => x.GetType().Name == "DataContractAttribute");
if (_arrayType.IsArray)
throw new InvalidOperationException("Jagged arrays are not supported");
if (_arrayType.IsGenericEnumerable())
throw new InvalidOperationException("Enumerables of enumerables are not supported");
Column = attr; Column = attr;
if (property.CanRead) if (property.CanRead)
@@ -121,43 +143,65 @@ namespace DynamORM.Mapper
/// <param name="val">The value.</param> /// <param name="val">The value.</param>
public void Set(object dest, object val) public void Set(object dest, object val)
{ {
Type type = Nullable.GetUnderlyingType(Type) ?? Type; object value = null;
bool nullable = Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>);
try try
{ {
if (val == null && type.IsValueType) if (Type.IsArray || _genericEnumerable)
{ {
if (nullable) var lst = (val as IEnumerable<object>).Select(x => GetElementVal(_arrayType, x)).ToList();
Setter(dest, null);
else value = Array.CreateInstance(_arrayType, lst.Count);
Setter(dest, Activator.CreateInstance(Type));
} int i = 0;
else if ((val == null && !type.IsValueType) || (val != null && type == val.GetType())) foreach (var e in lst)
Setter(dest, val); ((Array)value).SetValue(e, i++);
else if (type.IsEnum && val.GetType().IsValueType)
Setter(dest, Enum.ToObject(type, val));
else if (type.IsEnum)
Setter(dest, Enum.Parse(type, val.ToString()));
else if (Type == typeof(string) && val.GetType() == typeof(Guid))
Setter(dest, val.ToString());
else if (Type == typeof(Guid) && val.GetType() == typeof(string))
{
Guid g;
Setter(dest, Guid.TryParse((string)val, out g) ? g : Guid.Empty);
} }
else else
Setter(dest, Convert.ChangeType(val, type)); value = GetElementVal(Type, val);
Setter(dest, value);
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new InvalidCastException( throw new InvalidCastException(
string.Format("Error trying to convert value '{0}' of type '{1}' to value of type '{2}{3}' in object of type '{4}'", string.Format("Error trying to convert value '{0}' of type '{1}' to value of type '{2}' in object of type '{3}'",
val.ToString(), val.GetType(), type.FullName, nullable ? "(NULLABLE)" : string.Empty, dest.GetType().FullName), (val ?? string.Empty).ToString(), val.GetType(), Type.FullName, dest.GetType().FullName),
ex); ex);
} }
} }
private object GetElementVal(System.Type etype, object val)
{
bool nullable = etype.IsGenericType && etype.GetGenericTypeDefinition() == typeof(Nullable<>);
Type type = Nullable.GetUnderlyingType(etype) ?? etype;
if (val == null && type.IsValueType)
{
if (nullable)
return null;
else
return Activator.CreateInstance(Type);
}
else if ((val == null && !type.IsValueType) || (val != null && type == val.GetType()))
return val;
else if (type.IsEnum && val.GetType().IsValueType)
return Enum.ToObject(type, val);
else if (type.IsEnum)
return Enum.Parse(type, val.ToString());
else if (Type == typeof(string) && val.GetType() == typeof(Guid))
return val.ToString();
else if (Type == typeof(Guid) && val.GetType() == typeof(string))
{
Guid g;
return Guid.TryParse((string)val, out g) ? g : Guid.Empty;
}
else if (IsDataContract)
return val.Map(type);
else
return Convert.ChangeType(val, type);
}
#region Type command cache #region Type command cache
internal ParameterSpec InsertCommandParameter { get; set; } internal ParameterSpec InsertCommandParameter { get; set; }