This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,6 @@ namespace DynamORM.Builders.Implementation
|
||||
/// <summary>Implementation of dynamic select query builder.</summary>
|
||||
internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, DynamicQueryBuilder.IQueryWithWhere
|
||||
{
|
||||
private int? _top = null;
|
||||
private int? _limit = null;
|
||||
private int? _offset = null;
|
||||
private bool _distinct = false;
|
||||
@@ -83,17 +82,42 @@ namespace DynamORM.Builders.Implementation
|
||||
/// <returns>The text to execute against the underlying database.</returns>
|
||||
public override string CommandText()
|
||||
{
|
||||
bool lused = false;
|
||||
bool oused = false;
|
||||
|
||||
StringBuilder sb = new StringBuilder("SELECT");
|
||||
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 (_from != null) sb.AppendFormat(" FROM {0}", _from);
|
||||
if (_join != null) sb.AppendFormat(" {0}", _join);
|
||||
if (WhereCondition != null) sb.AppendFormat(" WHERE {0}", WhereCondition);
|
||||
if (_groupby != null) sb.AppendFormat(" GROUP BY {0}", _groupby);
|
||||
if (_orderby != null) sb.AppendFormat(" ORDER BY {0}", _orderby);
|
||||
if (_limit.HasValue) sb.AppendFormat(" LIMIT {0}", _limit);
|
||||
if (_offset.HasValue) sb.AppendFormat(" OFFSET {0}", _offset);
|
||||
if (_limit.HasValue && !lused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
|
||||
sb.AppendFormat(" LIMIT {0}", _limit);
|
||||
if (_offset.HasValue && !oused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset)
|
||||
sb.AppendFormat(" OFFSET {0}", _offset);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
@@ -1105,11 +1129,7 @@ namespace DynamORM.Builders.Implementation
|
||||
/// <returns>Builder instance.</returns>
|
||||
public virtual IDynamicSelectQueryBuilder Top(int? top)
|
||||
{
|
||||
if ((Database.Options & DynamicDatabaseOptions.SupportTop) != DynamicDatabaseOptions.SupportTop)
|
||||
throw new NotSupportedException("Database doesn't support TOP clause.");
|
||||
|
||||
_top = top;
|
||||
return this;
|
||||
return Limit(top);
|
||||
}
|
||||
|
||||
/// <summary>Set top if database support it.</summary>
|
||||
@@ -1117,7 +1137,9 @@ namespace DynamORM.Builders.Implementation
|
||||
/// <returns>Builder instance.</returns>
|
||||
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.");
|
||||
|
||||
_limit = limit;
|
||||
@@ -1129,7 +1151,8 @@ namespace DynamORM.Builders.Implementation
|
||||
/// <returns>Builder instance.</returns>
|
||||
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.");
|
||||
|
||||
_offset = offset;
|
||||
|
||||
@@ -50,11 +50,14 @@ namespace DynamORM
|
||||
/// <summary>Database supports limit offset syntax (SELECT ... FROM ... LIMIT x OFFSET y).</summary>
|
||||
SupportLimitOffset = 0x00000040,
|
||||
|
||||
/// <summary>Database supports limit offset syntax (SELECT FIRST x SKIP y ... FROM ...).</summary>
|
||||
SupportFirstSkip = 0x00000020,
|
||||
|
||||
/// <summary>Database support standard schema.</summary>
|
||||
SupportSchema = 0x00000010,
|
||||
|
||||
/// <summary>Database support stored procedures (EXEC procedure ...).</summary>
|
||||
SupportStoredProcedures = 0x00000020,
|
||||
SupportStoredProcedures = 0x00000100,
|
||||
|
||||
/// <summary>Debug option allowing to enable command dumps by default.</summary>
|
||||
DumpCommands = 0x01000000,
|
||||
|
||||
@@ -1283,7 +1283,7 @@ namespace DynamORM
|
||||
/// <returns>Returns <c>true</c> if it does.</returns>
|
||||
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<> interface.</summary>
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -45,6 +47,9 @@ namespace DynamORM.Mapper
|
||||
public int Ordinal { get; set; }
|
||||
}
|
||||
|
||||
private Type _arrayType;
|
||||
private bool _genericEnumerable;
|
||||
|
||||
/// <summary>Gets the type of property.</summary>
|
||||
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>
|
||||
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>
|
||||
/// <param name="property">Property info to be invoked in the future.</param>
|
||||
/// <param name="attr">Column attribute if exist.</param>
|
||||
@@ -75,6 +83,20 @@ namespace DynamORM.Mapper
|
||||
|
||||
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;
|
||||
|
||||
if (property.CanRead)
|
||||
@@ -121,43 +143,65 @@ namespace DynamORM.Mapper
|
||||
/// <param name="val">The value.</param>
|
||||
public void Set(object dest, object val)
|
||||
{
|
||||
Type type = Nullable.GetUnderlyingType(Type) ?? Type;
|
||||
bool nullable = Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||
object value = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (val == null && type.IsValueType)
|
||||
if (Type.IsArray || _genericEnumerable)
|
||||
{
|
||||
if (nullable)
|
||||
Setter(dest, null);
|
||||
else
|
||||
Setter(dest, Activator.CreateInstance(Type));
|
||||
}
|
||||
else if ((val == null && !type.IsValueType) || (val != null && type == val.GetType()))
|
||||
Setter(dest, val);
|
||||
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);
|
||||
var lst = (val as IEnumerable<object>).Select(x => GetElementVal(_arrayType, x)).ToList();
|
||||
|
||||
value = Array.CreateInstance(_arrayType, lst.Count);
|
||||
|
||||
int i = 0;
|
||||
foreach (var e in lst)
|
||||
((Array)value).SetValue(e, i++);
|
||||
}
|
||||
else
|
||||
Setter(dest, Convert.ChangeType(val, type));
|
||||
value = GetElementVal(Type, val);
|
||||
|
||||
Setter(dest, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
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}'",
|
||||
val.ToString(), val.GetType(), type.FullName, nullable ? "(NULLABLE)" : string.Empty, dest.GetType().FullName),
|
||||
string.Format("Error trying to convert value '{0}' of type '{1}' to value of type '{2}' in object of type '{3}'",
|
||||
(val ?? string.Empty).ToString(), val.GetType(), Type.FullName, dest.GetType().FullName),
|
||||
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
|
||||
|
||||
internal ParameterSpec InsertCommandParameter { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user