diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs
index 8bd0c6b..37db94a 100644
--- a/AmalgamationTool/DynamORM.Amalgamation.cs
+++ b/AmalgamationTool/DynamORM.Amalgamation.cs
@@ -48,12 +48,14 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
+using System.Text.RegularExpressions;
using DynamORM.Builders;
using DynamORM.Builders.Extensions;
using DynamORM.Builders.Implementation;
using DynamORM.Helpers;
using DynamORM.Helpers.Dynamics;
using DynamORM.Mapper;
+using DynamORM.Validation;
[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.")]
@@ -2857,6 +2859,7 @@ namespace DynamORM
{
case "varchar":
return DbType.AnsiString;
+
case "nvarchar":
return DbType.String;
}
@@ -5066,7 +5069,7 @@ namespace DynamORM
return defaultValue;
}
- /// Delegate fro try parse function of a type.
+ /// Delegate from try parse function of a type.
/// Type which implements this function.
/// Value to parse.
/// Resulting value.
@@ -6510,7 +6513,7 @@ namespace DynamORM
namespace Builders
{
/// Dynamic delete query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicDeleteQueryBuilder : IDynamicQueryBuilder
{
/// Execute this builder.
@@ -6556,7 +6559,7 @@ namespace DynamORM
}
/// Dynamic insert query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicInsertQueryBuilder : IDynamicQueryBuilder
{
/// Execute this builder.
@@ -6587,7 +6590,7 @@ namespace DynamORM
}
/// Dynamic query builder base interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicQueryBuilder : IExtendedDisposable
{
/// Gets instance.
@@ -6627,7 +6630,7 @@ namespace DynamORM
}
/// Dynamic select query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicSelectQueryBuilder : IDynamicQueryBuilder ////, IEnumerable
{
/// Execute this builder.
@@ -6881,7 +6884,7 @@ namespace DynamORM
}
/// Dynamic update query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicUpdateQueryBuilder : IDynamicQueryBuilder
{
/// Execute this builder.
@@ -12420,7 +12423,15 @@ namespace DynamORM
throw new ArgumentException(string.Format("Argument '{0}' must be dynamic.", p.Name));
}
- _uncertainResult = f.DynamicInvoke(_arguments.ToArray());
+ try
+ {
+ _uncertainResult = f.DynamicInvoke(_arguments.ToArray());
+ }
+ catch (TargetInvocationException e)
+ {
+ if (e.InnerException != null) throw e.InnerException;
+ else throw e;
+ }
}
///
@@ -13097,8 +13108,11 @@ namespace DynamORM
public int Ordinal { get; set; }
}
- private Type _arrayType;
- private bool _genericEnumerable;
+ /// Gets the array type of property if main type is a form of collection.
+ public Type ArrayType { get; private set; }
+
+ /// Gets a value indicating whether this property is in fact a generic list.
+ public bool IsGnericEnumerable { get; private set; }
/// Gets the type of property.
public Type Type { get; private set; }
@@ -13115,6 +13129,9 @@ namespace DynamORM
/// Gets type column description.
public ColumnAttribute Column { get; private set; }
+ /// Gets type list of property requirements.
+ public List Requirements { get; private set; }
+
/// Gets a value indicating whether this is ignored in some cases.
public bool Ignore { get; private set; }
@@ -13130,21 +13147,22 @@ namespace DynamORM
Type = property.PropertyType;
object[] ignore = property.GetCustomAttributes(typeof(IgnoreAttribute), false);
+ Requirements = property.GetCustomAttributes(typeof(RequiredAttribute), false).Cast().ToList();
Ignore = ignore != null && ignore.Length > 0;
- _arrayType = Type.IsArray ? Type.GetElementType() :
- Type.IsGenericEnumerable() ? Type.GetGenericArguments().First() :
+ IsGnericEnumerable = Type.IsGenericEnumerable();
+
+ ArrayType = Type.IsArray ? Type.GetElementType() :
+ IsGnericEnumerable ? Type.GetGenericArguments().First() :
Type;
- _genericEnumerable = Type.IsGenericEnumerable();
+ IsDataContract = ArrayType.GetCustomAttributes(false).Any(x => x.GetType().Name == "DataContractAttribute");
- IsDataContract = _arrayType.GetCustomAttributes(false).Any(x => x.GetType().Name == "DataContractAttribute");
-
- if (_arrayType.IsArray)
+ if (ArrayType.IsArray)
throw new InvalidOperationException("Jagged arrays are not supported");
- if (_arrayType.IsGenericEnumerable())
+ if (ArrayType.IsGenericEnumerable())
throw new InvalidOperationException("Enumerables of enumerables are not supported");
Column = attr;
@@ -13199,20 +13217,20 @@ namespace DynamORM
{
if (!Type.IsAssignableFrom(val.GetType()))
{
- if (Type.IsArray || _genericEnumerable)
+ if (Type.IsArray || IsGnericEnumerable)
{
if (val != null)
{
- var lst = (val as IEnumerable).Select(x => GetElementVal(_arrayType, x)).ToList();
+ var lst = (val as IEnumerable).Select(x => GetElementVal(ArrayType, x)).ToList();
- value = Array.CreateInstance(_arrayType, lst.Count);
+ value = Array.CreateInstance(ArrayType, lst.Count);
int i = 0;
foreach (var e in lst)
((Array)value).SetValue(e, i++);
}
else
- value = Array.CreateInstance(_arrayType, 0);
+ value = Array.CreateInstance(ArrayType, 0);
}
else
value = GetElementVal(Type, val);
@@ -13248,7 +13266,17 @@ namespace DynamORM
else if (type.IsEnum && val.GetType().IsValueType)
return Enum.ToObject(type, val);
else if (type.IsEnum)
- return Enum.Parse(type, val.ToString());
+ try
+ {
+ return Enum.Parse(type, val.ToString());
+ }
+ catch (ArgumentException)
+ {
+ if (nullable)
+ return null;
+
+ throw;
+ }
else if (Type == typeof(string) && val.GetType() == typeof(Guid))
return val.ToString();
else if (Type == typeof(Guid) && val.GetType() == typeof(string))
@@ -13259,7 +13287,17 @@ namespace DynamORM
else if (IsDataContract)
return val.Map(type);
else
- return Convert.ChangeType(val, type);
+ try
+ {
+ return Convert.ChangeType(val, type);
+ }
+ catch
+ {
+ if (nullable)
+ return null;
+
+ throw;
+ }
}
#region Type command cache
@@ -13377,6 +13415,57 @@ namespace DynamORM
return destination;
}
+ /// Validates the object.
+ /// The value.
+ /// List of not valid results.
+ public IList ValidateObject(object val)
+ {
+ var result = new List();
+
+ if (val == null || val.GetType() != Type)
+ return null;
+
+ foreach (var prop in ColumnsMap.Values)
+ {
+ if (prop.Requirements == null || !prop.Requirements.Any())
+ continue;
+
+ var v = prop.Get(val);
+
+ foreach (var r in prop.Requirements)
+ {
+ var valid = r.ValidateSimpleValue(prop, v);
+
+ if (valid == ValidateResult.Valid)
+ {
+ if (prop.Type.IsArray || prop.IsGnericEnumerable)
+ {
+ var map = DynamicMapperCache.GetMapper(prop.ArrayType);
+ foreach (var item in val as IEnumerable)
+ result.AddRange(map.ValidateObject(item));
+ }
+
+ continue;
+ }
+
+ if (valid == ValidateResult.NotSupported)
+ {
+ result.AddRange(DynamicMapperCache.GetMapper(prop.Type).ValidateObject(v));
+ continue;
+ }
+
+ result.Add(new ValidationResult()
+ {
+ Property = prop,
+ Requirement = r,
+ Value = v,
+ });
+ }
+ }
+
+ return result;
+ }
+
private IEnumerable GetAllMembers(Type type)
{
if (type.IsInterface)
@@ -13451,4 +13540,167 @@ namespace DynamORM
public bool Override { get; set; }
}
}
+
+ namespace Validation
+ {
+ /// Required attribute can be used to validate fields in objects using mapper class.
+ [AttributeUsage(AttributeTargets.Property)]
+ public class RequiredAttribute : Attribute
+ {
+ /// Gets or sets minimum value or length of field.
+ public decimal? Min { get; set; }
+
+ /// Gets or sets maximum value or length of field.
+ public decimal? Max { get; set; }
+
+ /// Gets or sets pattern to verify.
+ public Regex Pattern { get; set; }
+
+ /// Gets or sets a value indicating whether property value is required or not.
+ public bool Required { get; set; }
+
+ /// Initializes a new instance of the class.
+ /// This field will be required.
+ public RequiredAttribute(bool required = true)
+ {
+ Required = required;
+ }
+
+ /// Initializes a new instance of the class.
+ /// Limiting value to set.
+ /// Whether set maximum parameter (true) or minimum parameter (false).
+ /// This field will be required.
+ public RequiredAttribute(float val, bool max, bool required = true)
+ {
+ if (max)
+ Max = (decimal)val;
+ else
+ Min = (decimal)val;
+ Required = required;
+ }
+
+ /// Initializes a new instance of the class.
+ /// Minimum value to set.
+ /// Maximum value to set.
+ /// This field will be required.
+ public RequiredAttribute(float min, float max, bool required = true)
+ {
+ Min = (decimal)min;
+ Max = (decimal)max;
+ Required = required;
+ }
+
+ /// Initializes a new instance of the class.
+ /// Minimum value to set.
+ /// Maximum value to set.
+ /// Pattern to check.
+ /// This field will be required.
+ public RequiredAttribute(float min, float max, string pattern, bool required = true)
+ {
+ Min = (decimal)min;
+ Max = (decimal)max;
+ Pattern = new Regex(pattern, RegexOptions.Compiled);
+ Required = required;
+ }
+
+ internal ValidateResult ValidateSimpleValue(DynamicPropertyInvoker dpi, object val)
+ {
+ if (val == null && Required)
+ return ValidateResult.ValueIsMissing;
+
+ if (dpi.Type.IsValueType)
+ {
+ if (val is decimal || val is long || val is int || val is float || val is double || val is short || val is byte ||
+ val is decimal? || val is long? || val is int? || val is float? || val is double? || val is short? || val is byte?)
+ {
+ decimal dec = Convert.ToDecimal(val);
+
+ if (Min.HasValue && Min.Value > dec)
+ return ValidateResult.ValueTooSmall;
+
+ if (Max.HasValue && Max.Value < dec)
+ return ValidateResult.ValueTooLarge;
+
+ return ValidateResult.Valid;
+ }
+ else
+ {
+ var str = val.ToString();
+
+ if (Min.HasValue && Min.Value > str.Length)
+ return ValidateResult.ValueTooShort;
+
+ if (Max.HasValue && Max.Value < str.Length)
+ return ValidateResult.ValueTooLong;
+
+ if (Pattern != null && !Pattern.IsMatch(str))
+ return ValidateResult.ValueDontMatchPattern;
+
+ return ValidateResult.Valid;
+ }
+ }
+ else if (dpi.Type.IsArray || dpi.IsGnericEnumerable)
+ {
+ var cnt = (val as IEnumerable).Count();
+
+ if (Min.HasValue && Min.Value > cnt)
+ return ValidateResult.TooFewElementsInCollection;
+
+ if (Max.HasValue && Max.Value < cnt)
+ return ValidateResult.TooManyElementsInCollection;
+
+ return ValidateResult.Valid;
+ }
+
+ return ValidateResult.NotSupported;
+ }
+ }
+
+ /// Validation result enum.
+ public enum ValidateResult
+ {
+ /// The valid value.
+ Valid,
+
+ /// The value is missing.
+ ValueIsMissing,
+
+ /// The value too small.
+ ValueTooSmall,
+
+ /// The value too large.
+ ValueTooLarge,
+
+ /// The too few elements in collection.
+ TooFewElementsInCollection,
+
+ /// The too many elements in collection.
+ TooManyElementsInCollection,
+
+ /// The value too short.
+ ValueTooShort,
+
+ /// The value too long.
+ ValueTooLong,
+
+ /// The value don't match pattern.
+ ValueDontMatchPattern,
+
+ /// The not supported.
+ NotSupported,
+ }
+
+ /// Validation result.
+ public class ValidationResult
+ {
+ /// Gets the property invoker.
+ public DynamicPropertyInvoker Property { get; internal set; }
+
+ /// Gets the requirement definition.
+ public RequiredAttribute Requirement { get; internal set; }
+
+ /// Gets the value that is broken.
+ public object Value { get; internal set; }
+ }
+ }
}
\ No newline at end of file
diff --git a/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs b/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs
index 17629aa..915e2cb 100644
--- a/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs
+++ b/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs
@@ -31,7 +31,7 @@ using System;
namespace DynamORM.Builders
{
/// Dynamic delete query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicDeleteQueryBuilder : IDynamicQueryBuilder
{
/// Execute this builder.
diff --git a/DynamORM/Builders/IDynamicInsertQueryBuilder.cs b/DynamORM/Builders/IDynamicInsertQueryBuilder.cs
index e7e2cde..866f9e7 100644
--- a/DynamORM/Builders/IDynamicInsertQueryBuilder.cs
+++ b/DynamORM/Builders/IDynamicInsertQueryBuilder.cs
@@ -31,7 +31,7 @@ using System;
namespace DynamORM.Builders
{
/// Dynamic insert query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicInsertQueryBuilder : IDynamicQueryBuilder
{
/// Execute this builder.
diff --git a/DynamORM/Builders/IDynamicQueryBuilder.cs b/DynamORM/Builders/IDynamicQueryBuilder.cs
index 62b2554..4366bb3 100644
--- a/DynamORM/Builders/IDynamicQueryBuilder.cs
+++ b/DynamORM/Builders/IDynamicQueryBuilder.cs
@@ -34,7 +34,7 @@ using DynamORM.Helpers;
namespace DynamORM.Builders
{
/// Dynamic query builder base interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicQueryBuilder : IExtendedDisposable
{
/// Gets instance.
diff --git a/DynamORM/Builders/IDynamicSelectQueryBuilder.cs b/DynamORM/Builders/IDynamicSelectQueryBuilder.cs
index faabac2..4ca0448 100644
--- a/DynamORM/Builders/IDynamicSelectQueryBuilder.cs
+++ b/DynamORM/Builders/IDynamicSelectQueryBuilder.cs
@@ -33,7 +33,7 @@ using System.Data;
namespace DynamORM.Builders
{
/// Dynamic select query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicSelectQueryBuilder : IDynamicQueryBuilder ////, IEnumerable
{
/// Execute this builder.
diff --git a/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs b/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs
index 5f83381..5938a47 100644
--- a/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs
+++ b/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs
@@ -31,7 +31,7 @@ using System;
namespace DynamORM.Builders
{
/// Dynamic update query builder interface.
- /// This interface it publically available. Implementation should be hidden.
+ /// This interface it publicly available. Implementation should be hidden.
public interface IDynamicUpdateQueryBuilder : IDynamicQueryBuilder
{
/// Execute this builder.
diff --git a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs
index 012a0fb..4b4897c 100644
--- a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs
+++ b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs
@@ -227,7 +227,7 @@ namespace DynamORM.Builders.Implementation
reader(rdr);
}
- /// Execute this builder as a data reader, but
+ /// Execute this builder as a data reader, but
/// first makes a full reader copy in memory.
/// Action containing reader.
public virtual void ExecuteCachedDataReader(Action reader)
diff --git a/DynamORM/DynamORM.csproj b/DynamORM/DynamORM.csproj
index cf107bc..e4773c5 100644
--- a/DynamORM/DynamORM.csproj
+++ b/DynamORM/DynamORM.csproj
@@ -104,11 +104,14 @@
+
+
+