From 918aa702d39da46f5daba78cbe9e5dc139470746 Mon Sep 17 00:00:00 2001 From: Grzegorz Russek Date: Sat, 21 Feb 2026 10:03:59 +0100 Subject: [PATCH] Memory leaks fixed across the code related to cached reader. Copyright date bump --- AmalgamationTool/DynamORM.Amalgamation.cs | 4922 ++++++++++------- DynamORM.Tests/DynamORM.Tests.csproj | 2 +- DynamORM.Tests/Helpers/AttachToDebugger.cs | 2 +- .../Helpers/Dynamic/DynamicParserTests.cs | 2 +- DynamORM.Tests/Helpers/PoolingTests.cs | 2 +- DynamORM.Tests/Helpers/Users.cs | 2 +- DynamORM.Tests/Helpers/UsersBareBoneClass.cs | 2 +- .../Validation/ObjectValidationTest.cs | 2 +- .../Modify/DynamicModificationTests.cs | 2 +- .../DynamicNoSchemaModificationTests.cs | 2 +- .../DynamicTypeSchemaModificationTests.cs | 2 +- DynamORM.Tests/Modify/ParserTests.cs | 2 +- DynamORM.Tests/Select/DynamicAccessTests.cs | 2 +- .../Select/DynamicNoSchemaAccessTests.cs | 2 +- .../Select/DynamicTypeSchemaAccessTests.cs | 2 +- DynamORM.Tests/Select/LegacyParserTests.cs | 2 +- DynamORM.Tests/Select/ParserTests.cs | 2 +- .../Select/RenamedTypedAccessTests.cs | 2 +- DynamORM.Tests/Select/TypedAccessTests.cs | 2 +- DynamORM.Tests/TestsBase.cs | 2 +- .../DynamicHavingQueryExtensions.cs | 2 +- .../DynamicModifyBuilderExtensions.cs | 2 +- .../Extensions/DynamicWhereQueryExtensions.cs | 2 +- .../Builders/IDynamicDeleteQueryBuilder.cs | 2 +- .../Builders/IDynamicInsertQueryBuilder.cs | 2 +- DynamORM/Builders/IDynamicQueryBuilder.cs | 2 +- .../Builders/IDynamicSelectQueryBuilder.cs | 2 +- .../Builders/IDynamicUpdateQueryBuilder.cs | 2 +- DynamORM/Builders/IParameter.cs | 2 +- DynamORM/Builders/ITableInfo.cs | 2 +- .../DynamicDeleteQueryBuilder.cs | 2 +- .../DynamicInsertQueryBuilder.cs | 2 +- .../Implementation/DynamicModifyBuilder.cs | 2 +- .../Implementation/DynamicQueryBuilder.cs | 2 +- .../DynamicSelectQueryBuilder.cs | 99 +- .../DynamicUpdateQueryBuilder.cs | 2 +- DynamORM/DynamORM.csproj | 2 +- DynamORM/DynamicColumn.cs | 2 +- DynamORM/DynamicCommand.cs | 2 +- DynamORM/DynamicConnection.cs | 2 +- DynamORM/DynamicDatabase.cs | 82 +- DynamORM/DynamicDatabaseOptions.cs | 2 +- DynamORM/DynamicExpando.cs | 2 +- DynamORM/DynamicExtensions.cs | 2 +- DynamORM/DynamicProcedureInvoker.cs | 51 +- DynamORM/DynamicQueryException.cs | 2 +- DynamORM/DynamicSchemaColumn.cs | 2 +- DynamORM/DynamicTable.cs | 2 +- DynamORM/DynamicTransaction.cs | 2 +- DynamORM/Helpers/CollectionComparer.cs | 2 +- DynamORM/Helpers/Dynamics/DynamicParser.cs | 4 +- DynamORM/Helpers/Dynamics/DynamicProxy.cs | 2 +- DynamORM/Helpers/FrameworkTools.cs | 2 +- DynamORM/Helpers/IExtendedDisposable.cs | 2 +- DynamORM/Helpers/IFinalizerDisposable.cs | 2 +- DynamORM/Helpers/StringExtensions.cs | 2 +- DynamORM/Helpers/UnclassifiedExtensions.cs | 2 +- DynamORM/Mapper/ColumnAttribute.cs | 2 +- DynamORM/Mapper/DynamicCast.cs | 2 +- DynamORM/Mapper/DynamicMapperCache.cs | 2 +- DynamORM/Mapper/DynamicPropertyInvoker.cs | 2 +- DynamORM/Mapper/DynamicTypeMap.cs | 2 +- DynamORM/Mapper/IgnoreAttribute.cs | 2 +- DynamORM/Mapper/TableAttribute.cs | 2 +- DynamORM/Properties/AssemblyInfo.cs | 2 +- 65 files changed, 2942 insertions(+), 2336 deletions(-) diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs index 5a7d570..9be7b50 100644 --- a/AmalgamationTool/DynamORM.Amalgamation.cs +++ b/AmalgamationTool/DynamORM.Amalgamation.cs @@ -1,6 +1,6 @@ -/* +62/* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,6 +60,7 @@ using System; [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.")] + namespace DynamORM { /// Cache data reader in memory. @@ -94,7 +95,8 @@ namespace DynamORM /// The offset row. /// The limit to number of tows. -1 is no limit. /// The progress delegate. - public DynamicCachedReader(IDataReader reader, int offset = 0, int limit = -1, Func progress = null) + public DynamicCachedReader(IDataReader reader, int offset = 0, int limit = -1, + Func progress = null) { InitDataReader(reader, offset, limit, progress); } @@ -226,7 +228,8 @@ namespace DynamORM var mapper = DynamicMapperCache.GetMapper(elementType); if (mapper == null) - throw new InvalidCastException(string.Format("Object type '{0}' can't be mapped.", elementType.FullName)); + throw new InvalidCastException( + string.Format("Object type '{0}' can't be mapped.", elementType.FullName)); var r = new DynamicCachedReader(); r.Init(mapper.ColumnsMap.Count + 1); @@ -238,7 +241,8 @@ namespace DynamORM return r; } - private void InitDataReader(IDataReader reader, int offset = 0, int limit = -1, Func progress = null) + private void InitDataReader(IDataReader reader, int offset = 0, int limit = -1, + Func progress = null) { do { @@ -365,10 +369,15 @@ namespace DynamORM dr[2] = column.Value.Column.NullOr(x => x.Size ?? int.MaxValue, int.MaxValue); dr[3] = column.Value.Column.NullOr(x => x.Precision ?? 0, 0); dr[4] = column.Value.Column.NullOr(x => x.Scale ?? 0, 0); - dr[5] = column.Value.Column.NullOr(x => x.Type.HasValue ? x.Type.Value.ToType() : column.Value.Type, column.Value.Type); - dr[6] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), column.Value.Type.ToDbType()); - dr[7] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), column.Value.Type.ToDbType()); - dr[8] = column.Value.Column.NullOr(x => x.IsKey, false) ? true : column.Value.Column.NullOr(x => x.AllowNull, true); + dr[5] = column.Value.Column.NullOr(x => x.Type.HasValue ? x.Type.Value.ToType() : column.Value.Type, + column.Value.Type); + dr[6] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), + column.Value.Type.ToDbType()); + dr[7] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), + column.Value.Type.ToDbType()); + dr[8] = column.Value.Column.NullOr(x => x.IsKey, false) + ? true + : column.Value.Column.NullOr(x => x.AllowNull, true); dr[9] = column.Value.Column.NullOr(x => x.IsUnique, false); dr[10] = column.Value.Column.NullOr(x => x.IsKey, false); dr[11] = false; @@ -428,7 +437,8 @@ namespace DynamORM if (pos >= -1 && pos < _data[_currentDataPosition]._rows) { _data[_currentDataPosition]._position = pos; - _data[_currentDataPosition]._cachePos = _data[_currentDataPosition]._position * _data[_currentDataPosition]._fields; + _data[_currentDataPosition]._cachePos = + _data[_currentDataPosition]._position * _data[_currentDataPosition]._fields; } else throw new IndexOutOfRangeException(); @@ -487,7 +497,10 @@ namespace DynamORM /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. /// The number of rows changed, inserted, or deleted; 0 if no rows were affected or the statement /// failed; and -1 for SELECT statements. - public int RecordsAffected { get { return _data[_currentDataPosition]._rowsAffected; } } + public int RecordsAffected + { + get { return _data[_currentDataPosition]._rowsAffected; } + } #endregion IDataReader Members @@ -514,7 +527,10 @@ namespace DynamORM /// Gets the number of columns in the current row. /// When not positioned in a valid record set, 0; otherwise, the number of columns in the current record. The default is -1. - public int FieldCount { get { return _data[_currentDataPosition]._fields; } } + public int FieldCount + { + get { return _data[_currentDataPosition]._fields; } + } /// Return the value of the specified field. /// The index of the field to find. @@ -1170,7 +1186,9 @@ namespace DynamORM DynamicColumn ret = new DynamicColumn() { ColumnName = parts[0] }; if (parts.Length > 1) - ret.Order = parts[1].ToLower() == "d" || parts[1].ToLower() == "desc" ? SortOrder.Desc : SortOrder.Asc; + ret.Order = parts[1].ToLower() == "d" || parts[1].ToLower() == "desc" + ? SortOrder.Desc + : SortOrder.Asc; if (parts.Length > 2) ret.Alias = parts[2]; @@ -1207,9 +1225,9 @@ namespace DynamORM { sb.AppendFormat("{0}({1})", Aggregate, column); - alias = string.IsNullOrEmpty(alias) ? - ColumnName == "*" ? Guid.NewGuid().ToString() : ColumnName : - alias; + alias = string.IsNullOrEmpty(alias) + ? ColumnName == "*" ? Guid.NewGuid().ToString() : ColumnName + : alias; } else sb.Append(column); @@ -1327,17 +1345,29 @@ namespace DynamORM /// Gets or sets the text command to run against the data source. /// /// The text command to execute. The default value is an empty string (""). - public string CommandText { get { return _command.CommandText; } set { _command.CommandText = value; } } + public string CommandText + { + get { return _command.CommandText; } + set { _command.CommandText = value; } + } /// /// Gets or sets the wait time before terminating the attempt to execute a command and generating an error. /// /// The time (in seconds) to wait for the command to execute. The default value is 30 seconds. /// The property value assigned is less than 0. - public int CommandTimeout { get { return _commandTimeout ?? _command.CommandTimeout; } set { _commandTimeout = value; } } + public int CommandTimeout + { + get { return _commandTimeout ?? _command.CommandTimeout; } + set { _commandTimeout = value; } + } /// Gets or sets how the property is interpreted. - public CommandType CommandType { get { return _command.CommandType; } set { _command.CommandType = value; } } + public CommandType CommandType + { + get { return _command.CommandType; } + set { _command.CommandType = value; } + } /// Gets or sets the /// used by this instance of the . @@ -1361,7 +1391,8 @@ namespace DynamORM _command.Connection = null; } else - throw new InvalidOperationException("Can't assign direct IDbConnection implementation. This property accepts only DynamORM implementation of IDbConnection."); + throw new InvalidOperationException( + "Can't assign direct IDbConnection implementation. This property accepts only DynamORM implementation of IDbConnection."); } } @@ -1462,7 +1493,11 @@ namespace DynamORM /// object of a data provider executes. /// It's does nothing, transaction is peeked from transaction /// pool of a connection. This is only a dummy. - public IDbTransaction Transaction { get { return null; } set { } } + public IDbTransaction Transaction + { + get { return null; } + set { } + } /// Gets or sets how command results are applied to the /// when used by the @@ -1471,7 +1506,11 @@ namespace DynamORM /// Both unless the command is automatically generated. Then the default is None. /// The value entered was not one of the /// values. - public UpdateRowSource UpdatedRowSource { get { return _command.UpdatedRowSource; } set { _command.UpdatedRowSource = value; } } + public UpdateRowSource UpdatedRowSource + { + get { return _command.UpdatedRowSource; } + set { _command.UpdatedRowSource = value; } + } #endregion IDbCommand Members @@ -1725,10 +1764,21 @@ namespace DynamORM public DynamicDatabaseOptions Options { get; private set; } /// Gets or sets command timeout. - public int? CommandTimeout { get { return _commandTimeout; } set { _commandTimeout = value; _poolStamp = DateTime.Now.Ticks; } } + public int? CommandTimeout + { + get { return _commandTimeout; } + set + { + _commandTimeout = value; + _poolStamp = DateTime.Now.Ticks; + } + } /// Gets the database provider. - public DbProviderFactory Provider { get { return _provider; } } + public DbProviderFactory Provider + { + get { return _provider; } + } /// Gets the procedures invoker. /// @@ -1821,7 +1871,8 @@ namespace DynamORM { if (_proc == null) { - if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures) + if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != + DynamicDatabaseOptions.SupportStoredProcedures) throw new InvalidOperationException("Database connection doesn't support stored procedures."); _proc = new DynamicProcedureInvoker(this); @@ -1870,12 +1921,14 @@ namespace DynamORM DbProviderFactory provider = null; bool dispose = false; - var pi = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty); + var pi = type.GetProperty("Instance", + BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty); if (pi != null) provider = (DbProviderFactory)pi.GetValue(null, null); else { - var fi = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetField); + var fi = type.GetField("Instance", + BindingFlags.Static | BindingFlags.Public | BindingFlags.GetField); if (fi != null) provider = (DbProviderFactory)fi.GetValue(null); } @@ -1924,7 +1977,8 @@ namespace DynamORM TransactionPool.Add(connection, new Stack()); if (!_singleConnection) - throw new InvalidOperationException("This constructor accepts only connections with DynamicDatabaseOptions.SingleConnection option."); + throw new InvalidOperationException( + "This constructor accepts only connections with DynamicDatabaseOptions.SingleConnection option."); } private void InitCommon(string connectionString, DynamicDatabaseOptions options) @@ -1932,8 +1986,10 @@ namespace DynamORM _connectionString = connectionString; Options = options; - _singleConnection = (options & DynamicDatabaseOptions.SingleConnection) == DynamicDatabaseOptions.SingleConnection; - _singleTransaction = (options & DynamicDatabaseOptions.SingleTransaction) == DynamicDatabaseOptions.SingleTransaction; + _singleConnection = (options & DynamicDatabaseOptions.SingleConnection) == + DynamicDatabaseOptions.SingleConnection; + _singleTransaction = (options & DynamicDatabaseOptions.SingleTransaction) == + DynamicDatabaseOptions.SingleTransaction; DumpCommands = (options & DynamicDatabaseOptions.DumpCommands) == DynamicDatabaseOptions.DumpCommands; TransactionPool = new Dictionary>(); @@ -1986,8 +2042,8 @@ namespace DynamORM DynamicTable dt = null; lock (SyncLock) dt = TablesCache.TryGetValue(key) ?? - TablesCache.AddAndPassValue(key, - new DynamicTable(this, table, owner, keys)); + TablesCache.AddAndPassValue(key, + new DynamicTable(this, table, owner, keys)); return dt; } @@ -2006,8 +2062,8 @@ namespace DynamORM DynamicTable dt = null; lock (SyncLock) dt = TablesCache.TryGetValue(key) ?? - TablesCache.AddAndPassValue(key, - new DynamicTable(this, table, keys)); + TablesCache.AddAndPassValue(key, + new DynamicTable(this, table, keys)); return dt; } @@ -2016,7 +2072,8 @@ namespace DynamORM /// Disposed dynamic table. internal void RemoveFromCache(DynamicTable dynamicTable) { - foreach (KeyValuePair item in TablesCache.Where(kvp => kvp.Value == dynamicTable).ToList()) + foreach (KeyValuePair item in TablesCache.Where(kvp => kvp.Value == dynamicTable) + .ToList()) TablesCache.Remove(item.Key); } @@ -2147,15 +2204,16 @@ namespace DynamORM { try { - Dictionary parameters = new Dictionary(); + Dictionary parameters = + new Dictionary(); if (!string.IsNullOrEmpty(mapper.InsertCommandText)) { cmd.CommandText = mapper.InsertCommandText; foreach (DynamicPropertyInvoker col in mapper.ColumnsMap.Values - .Where(di => !di.Ignore && di.InsertCommandParameter != null) - .OrderBy(di => di.InsertCommandParameter.Ordinal)) + .Where(di => !di.Ignore && di.InsertCommandParameter != null) + .OrderBy(di => di.InsertCommandParameter.Ordinal)) { IDbDataParameter para = cmd.CreateParameter(); para.ParameterName = col.InsertCommandParameter.Name; @@ -2254,15 +2312,16 @@ namespace DynamORM { try { - Dictionary parameters = new Dictionary(); + Dictionary parameters = + new Dictionary(); if (!string.IsNullOrEmpty(mapper.UpdateCommandText)) { cmd.CommandText = mapper.UpdateCommandText; foreach (DynamicPropertyInvoker col in mapper.ColumnsMap.Values - .Where(di => !di.Ignore && di.UpdateCommandParameter != null) - .OrderBy(di => di.UpdateCommandParameter.Ordinal)) + .Where(di => !di.Ignore && di.UpdateCommandParameter != null) + .OrderBy(di => di.UpdateCommandParameter.Ordinal)) { IDbDataParameter para = cmd.CreateParameter(); para.ParameterName = col.UpdateCommandParameter.Name; @@ -2332,15 +2391,16 @@ namespace DynamORM { #region Update - Dictionary parametersUp = new Dictionary(); + Dictionary parametersUp = + new Dictionary(); if (!string.IsNullOrEmpty(mapper.UpdateCommandText)) { cmdUp.CommandText = mapper.UpdateCommandText; foreach (DynamicPropertyInvoker col in mapper.ColumnsMap.Values - .Where(di => !di.Ignore && di.UpdateCommandParameter != null) - .OrderBy(di => di.UpdateCommandParameter.Ordinal)) + .Where(di => !di.Ignore && di.UpdateCommandParameter != null) + .OrderBy(di => di.UpdateCommandParameter.Ordinal)) { IDbDataParameter para = cmdUp.CreateParameter(); para.ParameterName = col.UpdateCommandParameter.Name; @@ -2357,15 +2417,16 @@ namespace DynamORM #region Insert - Dictionary parametersIn = new Dictionary(); + Dictionary parametersIn = + new Dictionary(); if (!string.IsNullOrEmpty(mapper.InsertCommandText)) { cmdIn.CommandText = mapper.InsertCommandText; foreach (DynamicPropertyInvoker col in mapper.ColumnsMap.Values - .Where(di => !di.Ignore && di.InsertCommandParameter != null) - .OrderBy(di => di.InsertCommandParameter.Ordinal)) + .Where(di => !di.Ignore && di.InsertCommandParameter != null) + .OrderBy(di => di.InsertCommandParameter.Ordinal)) { IDbDataParameter para = cmdIn.CreateParameter(); para.ParameterName = col.InsertCommandParameter.Name; @@ -2475,15 +2536,16 @@ namespace DynamORM { try { - Dictionary parameters = new Dictionary(); + Dictionary parameters = + new Dictionary(); if (!string.IsNullOrEmpty(mapper.DeleteCommandText)) { cmd.CommandText = mapper.DeleteCommandText; foreach (DynamicPropertyInvoker col in mapper.ColumnsMap.Values - .Where(di => !di.Ignore && di.DeleteCommandParameter != null) - .OrderBy(di => di.DeleteCommandParameter.Ordinal)) + .Where(di => !di.Ignore && di.DeleteCommandParameter != null) + .OrderBy(di => di.DeleteCommandParameter.Ordinal)) { IDbDataParameter para = cmd.CreateParameter(); para.ParameterName = col.DeleteCommandParameter.Name; @@ -2524,12 +2586,14 @@ namespace DynamORM return affected; } - private void PrepareBatchInsert(DynamicTypeMap mapper, IDbCommand cmd, Dictionary parameters) + private void PrepareBatchInsert(DynamicTypeMap mapper, IDbCommand cmd, + Dictionary parameters) { PrepareBatchInsert(typeof(T), mapper, cmd, parameters); } - private void PrepareBatchInsert(Type t, DynamicTypeMap mapper, IDbCommand cmd, Dictionary parameters) + private void PrepareBatchInsert(Type t, DynamicTypeMap mapper, IDbCommand cmd, + Dictionary parameters) { DynamicPropertyInvoker currentprop = null; Dictionary temp = new Dictionary(); @@ -2576,12 +2640,14 @@ namespace DynamORM mapper.InsertCommandText = cmd.CommandText; } - private void PrepareBatchUpdate(DynamicTypeMap mapper, IDbCommand cmd, Dictionary parameters) + private void PrepareBatchUpdate(DynamicTypeMap mapper, IDbCommand cmd, + Dictionary parameters) { PrepareBatchUpdate(typeof(T), mapper, cmd, parameters); } - private void PrepareBatchUpdate(Type t, DynamicTypeMap mapper, IDbCommand cmd, Dictionary parameters) + private void PrepareBatchUpdate(Type t, DynamicTypeMap mapper, IDbCommand cmd, + Dictionary parameters) { DynamicPropertyInvoker currentprop = null; Dictionary temp = new Dictionary(); @@ -2654,12 +2720,14 @@ namespace DynamORM mapper.UpdateCommandText = cmd.CommandText; } - private void PrepareBatchDelete(DynamicTypeMap mapper, IDbCommand cmd, Dictionary parameters) + private void PrepareBatchDelete(DynamicTypeMap mapper, IDbCommand cmd, + Dictionary parameters) { PrepareBatchDelete(typeof(T), mapper, cmd, parameters); } - private void PrepareBatchDelete(Type t, DynamicTypeMap mapper, IDbCommand cmd, Dictionary parameters) + private void PrepareBatchDelete(Type t, DynamicTypeMap mapper, IDbCommand cmd, + Dictionary parameters) { DynamicPropertyInvoker currentprop = null; Dictionary temp = new Dictionary(); @@ -2741,7 +2809,8 @@ namespace DynamORM /// Number of affected rows. public virtual int Procedure(string procName, params object[] args) { - if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures) + if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != + DynamicDatabaseOptions.SupportStoredProcedures) throw new InvalidOperationException("Database connection desn't support stored procedures."); using (IDbConnection con = Open()) @@ -2760,7 +2829,8 @@ namespace DynamORM /// Number of affected rows. public virtual int Procedure(string procName, DynamicExpando args) { - if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures) + if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != + DynamicDatabaseOptions.SupportStoredProcedures) throw new InvalidOperationException("Database connection desn't support stored procedures."); using (IDbConnection con = Open()) @@ -2779,7 +2849,8 @@ namespace DynamORM /// Number of affected rows. public virtual int Procedure(string procName, ExpandoObject args) { - if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures) + if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != + DynamicDatabaseOptions.SupportStoredProcedures) throw new InvalidOperationException("Database connection desn't support stored procedures."); using (IDbConnection con = Open()) @@ -2841,8 +2912,8 @@ namespace DynamORM foreach (IDynamicQueryBuilder builder in builders) using (IDbCommand cmd = con.CreateCommand()) ret += cmd - .SetCommand(builder) - .ExecuteNonQuery(); + .SetCommand(builder) + .ExecuteNonQuery(); trans.Commit(); } @@ -2936,36 +3007,37 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(string sql, params object[] args) { - DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(sql) - .AddParameters(this, args) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.Read()) + .SetCommand(sql) + .AddParameters(this, args) + .ExecuteReader()) + using (IDataReader cache = new DynamicCachedReader(rdr)) { - dynamic val = null; - - // Work around to avoid yield being in try...catch block: - // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch - try + while (cache.Read()) { - val = cache.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); + dynamic val = null; - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } + // Work around to avoid yield being in try...catch block: + // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch + try + { + val = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); - yield return val; + throw new ArgumentException( + string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return val; + } } } } @@ -2975,36 +3047,35 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(IDynamicQueryBuilder builder) { - DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(builder) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.Read()) - { - dynamic val = null; - - // Work around to avoid yield being in try...catch block: - // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch - try + .SetCommand(builder) + .ExecuteReader()) + using (var cache = new DynamicCachedReader(rdr)) + while (cache.Read()) { - val = cache.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); + dynamic val = null; - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } + // Work around to avoid yield being in try...catch block: + // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch + try + { + val = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); - yield return val; - } + throw new ArgumentException( + string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return val; + } } } @@ -3024,9 +3095,9 @@ namespace DynamORM using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(sql) - .AddParameters(this, args) - .ExecuteReader()) + .SetCommand(sql) + .AddParameters(this, args) + .ExecuteReader()) return new DynamicCachedReader(rdr); } } @@ -3040,8 +3111,8 @@ namespace DynamORM using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(builder) - .ExecuteReader()) + .SetCommand(builder) + .ExecuteReader()) return new DynamicCachedReader(rdr); } } @@ -3085,7 +3156,7 @@ namespace DynamORM lock (SyncLock) schema = Schema.TryGetValue(table.ToLower()) ?? - BuildAndCacheSchema(table, null, owner); + BuildAndCacheSchema(table, null, owner); return schema; } @@ -3102,7 +3173,7 @@ namespace DynamORM lock (SyncLock) schema = Schema.TryGetValue(typeof(T).FullName) ?? - BuildAndCacheSchema(null, DynamicMapperCache.GetMapper()); + BuildAndCacheSchema(null, DynamicMapperCache.GetMapper()); return schema; } @@ -3119,7 +3190,7 @@ namespace DynamORM lock (SyncLock) schema = Schema.TryGetValue(table.FullName) ?? - BuildAndCacheSchema(null, DynamicMapperCache.GetMapper(table)); + BuildAndCacheSchema(null, DynamicMapperCache.GetMapper(table)); return schema; } @@ -3180,9 +3251,9 @@ namespace DynamORM { using (IDbConnection con = Open()) using (IDbCommand 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)))) + .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) .ToList(); } @@ -3243,21 +3314,24 @@ namespace DynamORM return DynamicExtensions.TypeMap.TryGetNullable(type) ?? DbType.String; } - private Dictionary BuildAndCacheSchema(string tableName, DynamicTypeMap mapper, string owner = null) + private Dictionary BuildAndCacheSchema(string tableName, DynamicTypeMap mapper, + string owner = null) { Dictionary schema = null; if (mapper != null) { - tableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - mapper.Type.Name : mapper.Table.Name; - owner = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) ? - null : mapper.Table.Owner; + tableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) + ? mapper.Type.Name + : mapper.Table.Name; + owner = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) ? null : mapper.Table.Owner; } bool databaseSchemaSupport = !string.IsNullOrEmpty(tableName) && - (Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema; - bool mapperSchema = mapper != null && mapper.Table != null && (mapper.Table.Override || !databaseSchemaSupport); + (Options & DynamicDatabaseOptions.SupportSchema) == + DynamicDatabaseOptions.SupportSchema; + bool mapperSchema = mapper != null && mapper.Table != null && + (mapper.Table.Override || !databaseSchemaSupport); #region Database schema @@ -3290,7 +3364,9 @@ namespace DynamORM return new DynamicSchemaColumn { Name = DynamicExtensions.Coalesce( - v.Value.Column == null || string.IsNullOrEmpty(v.Value.Column.Name) ? null : v.Value.Column.Name, + v.Value.Column == null || string.IsNullOrEmpty(v.Value.Column.Name) + ? null + : v.Value.Column.Name, col.HasValue && !string.IsNullOrEmpty(col.Value.Name) ? col.Value.Name : null, v.Value.Name), IsKey = DynamicExtensions.CoalesceNullable( @@ -3298,7 +3374,9 @@ namespace DynamORM col.HasValue ? col.Value.IsKey : false).Value, Type = DynamicExtensions.CoalesceNullable( v.Value.Column != null ? v.Value.Column.Type : null, - col.HasValue ? col.Value.Type : DynamicExtensions.TypeMap.TryGetNullable(v.Value.Type) ?? DbType.String).Value, + col.HasValue + ? col.Value.Type + : DynamicExtensions.TypeMap.TryGetNullable(v.Value.Type) ?? DbType.String).Value, IsUnique = DynamicExtensions.CoalesceNullable( v.Value.Column != null ? v.Value.Column.IsUnique : null, col.HasValue ? col.Value.IsUnique : false).Value, @@ -3326,14 +3404,29 @@ namespace DynamORM schema = mapper.ColumnsMap.ToDictionary(k => k.Key, v => new DynamicSchemaColumn { - Name = DynamicExtensions.Coalesce(v.Value.Column == null || string.IsNullOrEmpty(v.Value.Column.Name) ? null : v.Value.Column.Name, v.Value.Name), - IsKey = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.IsKey : false, false).Value, - Type = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.Type : null, DynamicExtensions.TypeMap.TryGetNullable(v.Value.Type) ?? DbType.String).Value, - IsUnique = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.IsUnique : null, false).Value, - AllowNull = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.AllowNull : true, true).Value, - Size = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.Size : null, 0).Value, - Precision = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.Precision : null, 0).Value, - Scale = DynamicExtensions.CoalesceNullable(v.Value.Column != null ? v.Value.Column.Scale : null, 0).Value, + Name = DynamicExtensions.Coalesce( + v.Value.Column == null || string.IsNullOrEmpty(v.Value.Column.Name) + ? null + : v.Value.Column.Name, v.Value.Name), + IsKey = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.IsKey : false, false) + .Value, + Type = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.Type : null, + DynamicExtensions.TypeMap.TryGetNullable(v.Value.Type) ?? DbType.String).Value, + IsUnique = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.IsUnique : null, false) + .Value, + AllowNull = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.AllowNull : true, true) + .Value, + Size = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.Size : null, 0).Value, + Precision = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.Precision : null, 0) + .Value, + Scale = DynamicExtensions + .CoalesceNullable(v.Value.Column != null ? v.Value.Column.Scale : null, 0).Value, }); #endregion MapEnumerable based only on type @@ -3377,7 +3470,11 @@ namespace DynamORM } /// Gets or sets parameter name format. - public string ParameterFormat { get { return _parameterFormat; } set { _parameterFormat = value; } } + public string ParameterFormat + { + get { return _parameterFormat; } + set { _parameterFormat = value; } + } /// Decorate string representing name of database object. /// Name of database object. @@ -3725,7 +3822,8 @@ namespace DynamORM } /// Dynamic expando is a simple and temporary class to resolve memory leaks inside ExpandoObject. - public class DynamicExpando : DynamicObject, IDictionary, ICollection>, IEnumerable>, IEnumerable + public class DynamicExpando : DynamicObject, IDictionary, ICollection>, + IEnumerable>, IEnumerable { /// Class containing information about last accessed property of dynamic object. public class PropertyAccess @@ -3833,11 +3931,21 @@ namespace DynamORM return _data.TryGetValue(key, out value); } - object IDictionary.this[string index] { get { return _data[index]; } set { _data[index] = value; } } + object IDictionary.this[string index] + { + get { return _data[index]; } + set { _data[index] = value; } + } - ICollection IDictionary.Keys { get { return _data.Keys; } } + ICollection IDictionary.Keys + { + get { return _data.Keys; } + } - ICollection IDictionary.Values { get { return _data.Values; } } + ICollection IDictionary.Values + { + get { return _data.Values; } + } #endregion IDictionary implementation @@ -3868,9 +3976,15 @@ namespace DynamORM return ((ICollection>)_data).Remove(item); } - int ICollection>.Count { get { return _data.Count; } } + int ICollection>.Count + { + get { return _data.Count; } + } - bool ICollection>.IsReadOnly { get { return ((ICollection>)_data).IsReadOnly; } } + bool ICollection>.IsReadOnly + { + get { return ((ICollection>)_data).IsReadOnly; } + } #endregion ICollection implementation @@ -3974,7 +4088,8 @@ namespace DynamORM /// The text command to run against the data source. /// Arguments used to format command. /// Returns edited instance. - public static IDbCommand SetCommand(this IDbCommand command, CommandType commandType, int commandTimeout, string commandText, params object[] args) + public static IDbCommand SetCommand(this IDbCommand command, CommandType commandType, int commandTimeout, + string commandText, params object[] args) { command.CommandType = commandType; command.CommandTimeout = commandTimeout; @@ -3993,7 +4108,8 @@ namespace DynamORM /// The text command to run against the data source. /// Arguments used to format command. /// Returns edited instance. - public static IDbCommand SetCommand(this IDbCommand command, int commandTimeout, string commandText, params object[] args) + public static IDbCommand SetCommand(this IDbCommand command, int commandTimeout, string commandText, + params object[] args) { command.CommandTimeout = commandTimeout; @@ -4011,7 +4127,8 @@ namespace DynamORM /// The text command to run against the data source. /// Arguments used to format command. /// Returns edited instance. - public static IDbCommand SetCommand(this IDbCommand command, CommandType commandType, string commandText, params object[] args) + public static IDbCommand SetCommand(this IDbCommand command, CommandType commandType, string commandText, + params object[] args) { command.CommandType = commandType; @@ -4153,7 +4270,8 @@ namespace DynamORM /// Column schema to use. /// Parameter value. /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand cmd, IDynamicQueryBuilder builder, DynamicSchemaColumn? col, object value) + public static IDbCommand AddParameter(this IDbCommand cmd, IDynamicQueryBuilder builder, + DynamicSchemaColumn? col, object value) { IDbDataParameter p = cmd.CreateParameter(); p.ParameterName = builder.Database.GetParameterName(cmd.Parameters.Count); @@ -4162,7 +4280,8 @@ namespace DynamORM { p.DbType = col.Value.Type; - if ((builder.Database.Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema) + if ((builder.Database.Options & DynamicDatabaseOptions.SupportSchema) == + DynamicDatabaseOptions.SupportSchema) { p.Size = col.Value.Size; p.Precision = col.Value.Precision; @@ -4200,14 +4319,17 @@ namespace DynamORM if (value == null || value == DBNull.Value) return DBNull.Value; - if ((type == DbType.String || type == DbType.AnsiString || type == DbType.StringFixedLength || type == DbType.AnsiStringFixedLength) && + if ((type == DbType.String || type == DbType.AnsiString || type == DbType.StringFixedLength || + type == DbType.AnsiStringFixedLength) && !(value is string)) return value.ToString(); else if (type == DbType.Guid && value is string) return Guid.Parse(value.ToString()); else if (type == DbType.Guid && value is byte[] && ((byte[])value).Length == 16) return new Guid((byte[])value); - else if (type == DbType.DateTime && value is TimeSpan) // HACK: This is specific for SQL Server, to be verified with other databases + else if + (type == DbType.DateTime && + value is TimeSpan) // HACK: This is specific for SQL Server, to be verified with other databases return DateTime.Today.Add((TimeSpan)value); return value; @@ -4276,7 +4398,9 @@ namespace DynamORM /// Indicates the scale of numeric parameters. /// The value of the . /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, ParameterDirection parameterDirection, DbType databaseType, int size, byte precision, byte scale, object value) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, + ParameterDirection parameterDirection, DbType databaseType, int size, byte precision, byte scale, + object value) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4300,7 +4424,8 @@ namespace DynamORM /// Indicates the precision of numeric parameters. /// Indicates the scale of numeric parameters. /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, ParameterDirection parameterDirection, DbType databaseType, int size, byte precision, byte scale) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, + ParameterDirection parameterDirection, DbType databaseType, int size, byte precision, byte scale) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4323,7 +4448,8 @@ namespace DynamORM /// Indicates the scale of numeric parameters. /// The value of the . /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, ParameterDirection parameterDirection, DbType databaseType, byte precision, byte scale, object value) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, + ParameterDirection parameterDirection, DbType databaseType, byte precision, byte scale, object value) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4345,7 +4471,8 @@ namespace DynamORM /// Indicates the scale of numeric parameters. /// The value of the . /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, byte precision, byte scale, object value) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, + byte precision, byte scale, object value) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4365,7 +4492,8 @@ namespace DynamORM /// Indicates the precision of numeric parameters. /// Indicates the scale of numeric parameters. /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, byte precision, byte scale) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, + byte precision, byte scale) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4385,7 +4513,8 @@ namespace DynamORM /// The size of the parameter. /// The value of the . /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, ParameterDirection parameterDirection, DbType databaseType, int size, object value) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, + ParameterDirection parameterDirection, DbType databaseType, int size, object value) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4405,7 +4534,8 @@ namespace DynamORM /// The size of the parameter. /// The value of the . /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, int size, object value) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, + int size, object value) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4423,7 +4553,8 @@ namespace DynamORM /// The of the . /// The value of the . /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, object value) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, + object value) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4440,7 +4571,8 @@ namespace DynamORM /// The of the . /// The size of the parameter. /// Returns edited instance. - public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, int size) + public static IDbCommand AddParameter(this IDbCommand command, string parameterName, DbType databaseType, + int size) { IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; @@ -4484,7 +4616,9 @@ namespace DynamORM } catch (Exception ex) { - throw new ArgumentException(string.Format("Error setting parameter {0} in command {1}", parameterName, command.CommandText ?? string.Empty), ex); + throw new ArgumentException( + string.Format("Error setting parameter {0} in command {1}", parameterName, + command.CommandText ?? string.Empty), ex); } return command; @@ -4504,7 +4638,9 @@ namespace DynamORM } catch (Exception ex) { - throw new ArgumentException(string.Format("Error setting parameter {0} in command {1}", index, command.CommandText ?? string.Empty), ex); + throw new ArgumentException( + string.Format("Error setting parameter {0} in command {1}", index, + command.CommandText ?? string.Empty), ex); } return command; @@ -4551,7 +4687,8 @@ namespace DynamORM /// Default result value. /// Handler of a try parse method. /// Returns resulting instance of T from query. - public static T ExecuteScalarAs(this IDbCommand command, T defaultValue, DynamicExtensions.TryParseHandler handler) + public static T ExecuteScalarAs(this IDbCommand command, T defaultValue, + DynamicExtensions.TryParseHandler handler) { T ret = defaultValue; @@ -4606,7 +4743,8 @@ namespace DynamORM /// Default result value. /// Handler of a try parse method. /// Returns enumerator of specified type from query. - public static IEnumerable ExecuteEnumeratorOf(this IDbCommand command, T defaultValue, DynamicExtensions.TryParseHandler handler) where T : struct + public static IEnumerable ExecuteEnumeratorOf(this IDbCommand command, T defaultValue, + DynamicExtensions.TryParseHandler handler) where T : struct { using (IDataReader reader = command.ExecuteReader()) { @@ -4652,7 +4790,8 @@ namespace DynamORM return (bool)method.Invoke(null, new object[] { v, r }); }); else - throw new InvalidOperationException("Provided type can't be parsed using generic approach."); + throw new InvalidOperationException( + "Provided type can't be parsed using generic approach."); } } @@ -4693,7 +4832,8 @@ namespace DynamORM { try { - writer.WriteLine("Type: {0}; Timeout: {1}; Query: {2}", command.CommandType, command.CommandTimeout, command.CommandText); + writer.WriteLine("Type: {0}; Timeout: {1}; Query: {2}", command.CommandType, command.CommandTimeout, + command.CommandText); if (command.Parameters.Count > 0) { @@ -4707,7 +4847,9 @@ namespace DynamORM param.Scale, param.Precision, param.Scale, - param.Value is byte[] ? ConvertByteArrayToHexString((byte[])param.Value) : param.Value ?? "NULL", + param.Value is byte[] + ? ConvertByteArrayToHexString((byte[])param.Value) + : param.Value ?? "NULL", param.Value != null ? param.Value.GetType().Name : "DBNull"); } @@ -4792,7 +4934,8 @@ namespace DynamORM /// The builder on which set delegate. /// Action to invoke. /// Returns instance of builder on which action is set. - public static T CreateParameterAction(this T b, Action a) where T : IDynamicQueryBuilder + public static T CreateParameterAction(this T b, Action a) + where T : IDynamicQueryBuilder { if (a != null) { @@ -4831,7 +4974,8 @@ namespace DynamORM /// The specification for sub query. /// The specification for sub query. /// Instance of sub query. - public static IDynamicSelectQueryBuilder SubQuery(this T b, Func fn, params Func[] func) where T : IDynamicQueryBuilder + public static IDynamicSelectQueryBuilder SubQuery(this T b, Func fn, + params Func[] func) where T : IDynamicQueryBuilder { return new DynamicSelectQueryBuilder(b.Database, b as DynamicQueryBuilder).From(fn, func); } @@ -4841,7 +4985,8 @@ namespace DynamORM /// The builder that will be parent of new sub query. /// First argument is parent query, second one is a sub query. /// This instance to permit chaining. - public static T SubQuery(this T b, Action subquery) where T : IDynamicQueryBuilder + public static T SubQuery(this T b, Action subquery) + where T : IDynamicQueryBuilder { IDynamicSelectQueryBuilder sub = b.SubQuery(); @@ -4865,7 +5010,8 @@ namespace DynamORM /// The specification for sub query. /// The specification for sub query. /// This instance to permit chaining. - public static T SubQuery(this T b, Action subquery, Func fn, params Func[] func) where T : IDynamicQueryBuilder + public static T SubQuery(this T b, Action subquery, Func fn, + params Func[] func) where T : IDynamicQueryBuilder { IDynamicSelectQueryBuilder sub = b.SubQuery(fn, func); @@ -4886,7 +5032,7 @@ namespace DynamORM public static List ToList(this IDataReader r) { List result = new List(); - + while (r.Read()) result.Add(r.RowToDynamic()); @@ -5057,7 +5203,8 @@ namespace DynamORM int len = r.Table.Columns.Count; for (int i = 0; i < len; i++) - ((IDictionary)e).Add(r.Table.Columns[i].ColumnName.ToUpper(), r.IsNull(i) ? null : r[i]); + ((IDictionary)e).Add(r.Table.Columns[i].ColumnName.ToUpper(), + r.IsNull(i) ? null : r[i]); return e; } @@ -5073,7 +5220,8 @@ namespace DynamORM int len = r.Table.Columns.Count; for (int i = 0; i < len; i++) - ((IDictionary)e).Add(r.Table.Columns[i].ColumnName.ToUpper(), r.IsNull(i) ? null : r[i]); + ((IDictionary)e).Add(r.Table.Columns[i].ColumnName.ToUpper(), + r.IsNull(i) ? null : r[i]); return e; } @@ -5107,7 +5255,8 @@ namespace DynamORM catch (ArgumentException argex) { throw new ArgumentException( - string.Format("Field '{0}' is defined more than once in a query.", r.GetName(i)), "Column name or alias", argex); + string.Format("Field '{0}' is defined more than once in a query.", r.GetName(i)), + "Column name or alias", argex); } return e; @@ -5130,7 +5279,8 @@ namespace DynamORM catch (ArgumentException argex) { throw new ArgumentException( - string.Format("Field '{0}' is defined more than once in a query.", r.GetName(i)), "Column name or alias", argex); + string.Format("Field '{0}' is defined more than once in a query.", r.GetName(i)), + "Column name or alias", argex); } return e; @@ -5157,9 +5307,9 @@ namespace DynamORM /// Resulting dictionary. public static IDictionary ToDictionary(this object o) { - return o is IDictionary ? - (IDictionary)o : - (IDictionary)o.ToDynamic(); + return o is IDictionary + ? (IDictionary)o + : (IDictionary)o.ToDynamic(); } #endregion Dynamic extensions @@ -5173,10 +5323,10 @@ namespace DynamORM { // HACK: The only way to detect anonymous types right now. return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false) - && type.IsGenericType - && (type.Name.Contains("AnonymousType") || type.Name.Contains("AnonType")) - && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) - && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; + && type.IsGenericType + && (type.Name.Contains("AnonymousType") || type.Name.Contains("AnonType")) + && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) + && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; } /// Check if type implements IEnumerable<> interface. @@ -5184,7 +5334,8 @@ namespace DynamORM /// Returns true if it does. public static bool IsGenericEnumerable(this Type type) { - return type.IsGenericType && type.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)); + return type.IsGenericType && type.GetInterfaces() + .Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>)); } /// Check if type implements IEnumerable<> interface. @@ -5194,7 +5345,8 @@ namespace DynamORM { Type generic = type.IsGenericType ? type.GetGenericTypeDefinition() : null; - if (generic != null && generic.Equals(typeof(Nullable<>)) && (type.IsClass || type.IsValueType || type.IsEnum)) + if (generic != null && generic.Equals(typeof(Nullable<>)) && + (type.IsClass || type.IsValueType || type.IsEnum)) return true; return false; @@ -5220,7 +5372,8 @@ namespace DynamORM return type.GetElementType().IsValueType; else { - if (type.IsGenericType && type.GetInterfaces().Any(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))) + if (type.IsGenericType && + type.GetInterfaces().Any(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))) { Type[] gt = type.GetGenericArguments(); @@ -5276,7 +5429,8 @@ namespace DynamORM /// Dictionary to probe. /// The key whose value to get. /// Nullable type containing value or null if key was not found. - public static TValue? TryGetNullable(this IDictionary dict, TKey key) where TValue : struct + public static TValue? TryGetNullable(this IDictionary dict, TKey key) + where TValue : struct { TValue val; @@ -5292,7 +5446,8 @@ namespace DynamORM /// Dictionary to probe. /// The key whose value to get. /// Instance of object or null if not found. - public static TValue TryGetValue(this IDictionary dict, TKey key) where TValue : class + public static TValue TryGetValue(this IDictionary dict, TKey key) + where TValue : class { TValue val; @@ -5344,7 +5499,8 @@ namespace DynamORM /// The limit to number of tows. -1 is no limit. /// The progress delegate. /// Returns new instance of cached reader or current instance of a reader. - public static IDataReader CachedReader(this IDataReader r, int offset = 0, int limit = -1, Func progress = null) + public static IDataReader CachedReader(this IDataReader r, int offset = 0, int limit = -1, + Func progress = null) { if (r is DynamicCachedReader) return r; @@ -5663,7 +5819,8 @@ namespace DynamORM if (_prefixes == null || _prefixes.Count == 0) cmd.SetCommand(CommandType.StoredProcedure, binder.Name); else - cmd.SetCommand(CommandType.StoredProcedure, string.Format("{0}.{1}", string.Join(".", _prefixes), binder.Name)); + cmd.SetCommand(CommandType.StoredProcedure, + string.Format("{0}.{1}", string.Join(".", _prefixes), binder.Name)); #region Prepare arguments @@ -5695,8 +5852,7 @@ namespace DynamORM isRet = info.ArgumentNames[i].StartsWith("ret_"); isBoth = info.ArgumentNames[i].StartsWith("both_"); - paramName = isOut || isRet ? - info.ArgumentNames[i].Substring(4) : + paramName = isOut || isRet ? info.ArgumentNames[i].Substring(4) : isBoth ? info.ArgumentNames[i].Substring(5) : info.ArgumentNames[i]; } @@ -5728,9 +5884,9 @@ namespace DynamORM cmd.AddParameter( _db.GetParameterName(paramName), isOut ? ParameterDirection.Output : - isRet ? ParameterDirection.ReturnValue : - isBoth ? ParameterDirection.InputOutput : - ParameterDirection.Input, + isRet ? ParameterDirection.ReturnValue : + isBoth ? ParameterDirection.InputOutput : + ParameterDirection.Input, ds.Type, ds.Size, ds.Precision, ds.Scale, (isOut || isRet) ? DBNull.Value : dcv.Value); } @@ -5738,9 +5894,9 @@ namespace DynamORM cmd.AddParameter( _db.GetParameterName(paramName), isOut ? ParameterDirection.Output : - isRet ? ParameterDirection.ReturnValue : - isBoth ? ParameterDirection.InputOutput : - ParameterDirection.Input, + isRet ? ParameterDirection.ReturnValue : + isBoth ? ParameterDirection.InputOutput : + ParameterDirection.Input, arg == null ? DbType.String : arg.GetType().ToDbType(), isRet ? 4 : 0, (isOut || isRet) ? DBNull.Value : dcv.Value); @@ -5760,8 +5916,7 @@ namespace DynamORM isRet = info.ArgumentNames[i].StartsWith("ret_"); isBoth = info.ArgumentNames[i].StartsWith("both_"); - paramName = isOut || isRet ? - info.ArgumentNames[i].Substring(4) : + paramName = isOut || isRet ? info.ArgumentNames[i].Substring(4) : isBoth ? info.ArgumentNames[i].Substring(5) : info.ArgumentNames[i]; } @@ -5781,9 +5936,9 @@ namespace DynamORM cmd.AddParameter( _db.GetParameterName(paramName), isOut ? ParameterDirection.Output : - isRet ? ParameterDirection.ReturnValue : - isBoth ? ParameterDirection.InputOutput : - ParameterDirection.Input, + isRet ? ParameterDirection.ReturnValue : + isBoth ? ParameterDirection.InputOutput : + ParameterDirection.Input, dsc.Type, dsc.Size, dsc.Precision, dsc.Scale, DBNull.Value); } @@ -5798,8 +5953,7 @@ namespace DynamORM if (isRet) retIsAdded = true; - string paramName = isOut || isRet ? - info.ArgumentNames[i].Substring(4) : + string paramName = isOut || isRet ? info.ArgumentNames[i].Substring(4) : isBoth ? info.ArgumentNames[i].Substring(5) : info.ArgumentNames[i]; @@ -5813,9 +5967,9 @@ namespace DynamORM cmd.AddParameter( _db.GetParameterName(paramName), isOut ? ParameterDirection.Output : - isRet ? ParameterDirection.ReturnValue : - isBoth ? ParameterDirection.InputOutput : - ParameterDirection.Input, + isRet ? ParameterDirection.ReturnValue : + isBoth ? ParameterDirection.InputOutput : + ParameterDirection.Input, arg == null ? isRet ? DbType.Int32 : DbType.String : arg.GetType().ToDbType(), isRet ? 4 : 0, (isOut || isRet) ? DBNull.Value : arg); @@ -5844,18 +5998,17 @@ namespace DynamORM else if (types[0] == typeof(DataTable)) { using (IDataReader rdr = cmd.ExecuteReader()) - mainResult = rdr.CachedReader().ToDataTable(binder.Name); + using (IDataReader cache = rdr.CachedReader()) + mainResult = cache.ToDataTable(binder.Name); } else if (types[0].IsGenericEnumerable()) { Type argType = types[0].GetGenericArguments().First(); if (argType == typeof(object)) { - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); - - mainResult = cache.EnumerateReader().ToList(); + using (IDataReader cache = rdr.CachedReader()) + mainResult = cache.EnumerateReader().ToList(); } else if (argType.IsValueType || argType == typeof(string)) { @@ -5864,12 +6017,12 @@ namespace DynamORM object defVal = listType.GetDefaultValue(); - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); - - while (cache.Read()) - listInstance.Add(cache[0] != null && cache[0] != DBNull.Value ? argType.CastObject(cache[0]) : defVal); + using (IDataReader cache = rdr.CachedReader()) + while (cache.Read()) + listInstance.Add(cache[0] != null && cache[0] != DBNull.Value + ? argType.CastObject(cache[0]) + : defVal); mainResult = listInstance; } @@ -5880,15 +6033,14 @@ namespace DynamORM object defVal = listType.GetDefaultValue(); - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); - - while (cache.Read()) - { - if (cache[0] != null && cache[0] != DBNull.Value && Guid.TryParse(cache[0].ToString(), out Guid g)) - listInstance.Add(g); - } + using (IDataReader cache = rdr.CachedReader()) + while (cache.Read()) + { + if (cache[0] != null && cache[0] != DBNull.Value && + Guid.TryParse(cache[0].ToString(), out Guid g)) + listInstance.Add(g); + } mainResult = listInstance; } @@ -5896,20 +6048,21 @@ namespace DynamORM { DynamicTypeMap mapper = DynamicMapperCache.GetMapper(argType); if (mapper == null) - throw new InvalidCastException(string.Format("Don't know what to do with this type: '{0}'.", argType.ToString())); + throw new InvalidCastException( + string.Format("Don't know what to do with this type: '{0}'.", argType.ToString())); - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); + using (IDataReader cache = rdr.CachedReader()) + { + var lt = typeof(List<>); + var ltc = lt.MakeGenericType(argType); + var instance = Activator.CreateInstance(ltc) as IList; - var lt = typeof(List<>); - var ltc = lt.MakeGenericType(argType); - var instance = Activator.CreateInstance(ltc) as IList; + foreach (var item in cache.EnumerateReader()) + instance.Add(DynamicExtensions.Map(item, argType)); - foreach (var item in cache.EnumerateReader()) - instance.Add(DynamicExtensions.Map(item, argType)); - - mainResult = instance; + mainResult = instance; + } //mainResult = cache.EnumerateReader().MapEnumerable(argType).ToList(); } @@ -5923,14 +6076,16 @@ namespace DynamORM else if (types[0] == typeof(Guid)) { mainResult = cmd.ExecuteScalar(); - if (mainResult != null && mainResult != DBNull.Value && Guid.TryParse(mainResult.ToString(), out Guid g)) + if (mainResult != null && mainResult != DBNull.Value && + Guid.TryParse(mainResult.ToString(), out Guid g)) mainResult = g; } else { DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[0]); if (mapper == null) - throw new InvalidCastException(string.Format("Don't know what to do with this type: '{0}'.", types[0].ToString())); + throw new InvalidCastException(string.Format("Don't know what to do with this type: '{0}'.", + types[0].ToString())); using (IDataReader rdr = cmd.ExecuteReader()) if (rdr.Read()) @@ -5942,10 +6097,12 @@ namespace DynamORM else { var returnName = _db.GetParameterName("___result___"); - if ((_db.Options & DynamicDatabaseOptions.SupportStoredProceduresResult) == DynamicDatabaseOptions.SupportStoredProceduresResult) + if ((_db.Options & DynamicDatabaseOptions.SupportStoredProceduresResult) == + DynamicDatabaseOptions.SupportStoredProceduresResult) { if (!retIsAdded) - cmd.AddParameter(returnName, ParameterDirection.ReturnValue, DbType.Int32, 4, 0, 0, DBNull.Value); + cmd.AddParameter(returnName, ParameterDirection.ReturnValue, DbType.Int32, 4, 0, 0, + DBNull.Value); } mainResult = cmd.ExecuteNonQuery(); @@ -5953,7 +6110,8 @@ namespace DynamORM IDbDataParameter returnParam = null; if (!retIsAdded) { - if ((_db.Options & DynamicDatabaseOptions.SupportStoredProceduresResult) == DynamicDatabaseOptions.SupportStoredProceduresResult) + if ((_db.Options & DynamicDatabaseOptions.SupportStoredProceduresResult) == + DynamicDatabaseOptions.SupportStoredProceduresResult) returnParam = cmd.Parameters[returnName] as IDbDataParameter; } else @@ -6028,7 +6186,8 @@ namespace DynamORM /// class. /// The command which failed. public DynamicQueryException(IDbCommand command = null) - : base(string.Format("Error executing command.{0}{1}", Environment.NewLine, command != null ? command.DumpToString() : string.Empty)) + : base(string.Format("Error executing command.{0}{1}", Environment.NewLine, + command != null ? command.DumpToString() : string.Empty)) { } @@ -6037,7 +6196,8 @@ namespace DynamORM /// The message. /// The command which failed. public DynamicQueryException(string message, IDbCommand command = null) - : base(string.Format("{0}{1}{2}", message, Environment.NewLine, command != null ? command.DumpToString() : string.Empty)) + : base(string.Format("{0}{1}{2}", message, Environment.NewLine, + command != null ? command.DumpToString() : string.Empty)) { } @@ -6046,7 +6206,9 @@ namespace DynamORM /// The inner exception. /// The command which failed. public DynamicQueryException(Exception innerException, IDbCommand command = null) - : base(string.Format("Error executing command.{0}{1}", Environment.NewLine, command != null ? command.DumpToString() : string.Empty), innerException) + : base( + string.Format("Error executing command.{0}{1}", Environment.NewLine, + command != null ? command.DumpToString() : string.Empty), innerException) { } @@ -6056,7 +6218,9 @@ namespace DynamORM /// The inner exception. /// The command which failed. public DynamicQueryException(string message, Exception innerException, IDbCommand command = null) - : base(string.Format("{0}{1}{2}", message, Environment.NewLine, command != null ? command.DumpToString() : string.Empty), innerException) + : base( + string.Format("{0}{1}{2}", message, Environment.NewLine, + command != null ? command.DumpToString() : string.Empty), innerException) { } } @@ -6273,8 +6437,8 @@ namespace DynamORM { get { - return string.IsNullOrEmpty(TableName) ? null : string.IsNullOrEmpty(OwnerName) ? - Database.DecorateName(TableName) : + return string.IsNullOrEmpty(TableName) ? null : + string.IsNullOrEmpty(OwnerName) ? Database.DecorateName(TableName) : string.Format("{0}.{1}", Database.DecorateName(OwnerName), Database.DecorateName(TableName)); } } @@ -6321,10 +6485,12 @@ namespace DynamORM if (mapper != null) { - TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - type.Name : mapper.Table.Name; - OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) ? - null : mapper.Table.Owner; + TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) + ? type.Name + : mapper.Table.Name; + OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Owner) + ? null + : mapper.Table.Owner; } BuildAndCacheSchema(keys); @@ -6337,7 +6503,7 @@ namespace DynamORM Dictionary schema = null; schema = Database.GetSchema(TableType) ?? - Database.GetSchema(TableName, OwnerName); + Database.GetSchema(TableName, OwnerName); #region Fill currrent table schema @@ -6347,7 +6513,8 @@ namespace DynamORM if (mapper != null) { - IEnumerable k = mapper.ColumnsMap.Where(p => p.Value.Column != null && p.Value.Column.IsKey).Select(p => p.Key); + IEnumerable k = mapper.ColumnsMap.Where(p => p.Value.Column != null && p.Value.Column.IsKey) + .Select(p => p.Key); if (k.Count() > 0) keys = k.ToArray(); } @@ -6535,7 +6702,8 @@ namespace DynamORM /// New instance. public dynamic Insert() { - return new DynamicProxy(new DynamicInsertQueryBuilder(this.Database, this.FullName)); + return new DynamicProxy( + new DynamicInsertQueryBuilder(this.Database, this.FullName)); } /// Adds a record to the database. You can pass in an Anonymous object, an , @@ -6558,7 +6726,8 @@ namespace DynamORM /// New instance. public dynamic Update() { - return new DynamicProxy(new DynamicUpdateQueryBuilder(this.Database, this.FullName)); + return new DynamicProxy( + new DynamicUpdateQueryBuilder(this.Database, this.FullName)); } /// Updates a record in the database. You can pass in an Anonymous object, an ExpandoObject, @@ -6596,7 +6765,8 @@ namespace DynamORM /// New instance. public dynamic Delete() { - return new DynamicProxy(new DynamicDeleteQueryBuilder(this.Database, this.FullName)); + return new DynamicProxy( + new DynamicDeleteQueryBuilder(this.Database, this.FullName)); } /// Removes a record from the database. You can pass in an Anonymous object, an , @@ -6632,7 +6802,8 @@ namespace DynamORM // accepting named args only... SKEET! if (info.ArgumentNames.Count != args.Length) - throw new InvalidOperationException("Please use named arguments for this type of query - the column name, orderby, columns, etc"); + throw new InvalidOperationException( + "Please use named arguments for this type of query - the column name, orderby, columns, etc"); string op = binder.Name; @@ -6670,7 +6841,10 @@ namespace DynamORM HandleTypeArgument(null, info, ref types, builder, 0); if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0) - builder.Table(string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema); + builder.Table( + string.IsNullOrEmpty(this.OwnerName) + ? this.TableName + : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema); // loop the named args - see if we have order, columns and constraints if (info.ArgumentNames.Count > 0) @@ -6717,7 +6891,10 @@ namespace DynamORM HandleTypeArgument(null, info, ref types, builder, 0); if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0) - builder.Table(string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema); + builder.Table( + string.IsNullOrEmpty(this.OwnerName) + ? this.TableName + : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema); // loop the named args - see if we have order, columns and constraints if (info.ArgumentNames.Count > 0) @@ -6772,7 +6949,10 @@ namespace DynamORM HandleTypeArgument(null, info, ref types, builder, 0); if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0) - builder.Table(string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema); + builder.Table( + string.IsNullOrEmpty(this.OwnerName) + ? this.TableName + : string.Format("{0}.{1}", this.OwnerName, this.TableName), this.Schema); // loop the named args - see if we have order, columns and constraints if (info.ArgumentNames.Count > 0) @@ -6824,7 +7004,10 @@ namespace DynamORM HandleTypeArgument(null, info, ref types, builder, 0); if (!string.IsNullOrEmpty(this.TableName) && builder.Tables.Count == 0) - builder.From(x => string.IsNullOrEmpty(this.OwnerName) ? this.TableName : string.Format("{0}.{1}", this.OwnerName, this.TableName)); + builder.From(x => + string.IsNullOrEmpty(this.OwnerName) + ? this.TableName + : string.Format("{0}.{1}", this.OwnerName, this.TableName)); // loop the named args - see if we have order, columns and constraints if (info.ArgumentNames.Count > 0) @@ -6862,31 +7045,34 @@ namespace DynamORM break; case "columns": - { - string agregate = (op == "Sum" || op == "Max" || op == "Min" || op == "Avg" || op == "Count") ? - op.ToUpper() : null; + { + string agregate = + (op == "Sum" || op == "Max" || op == "Min" || op == "Avg" || op == "Count") + ? op.ToUpper() + : null; - if (args[i] is string || args[i] is string[]) - builder.SelectColumn((args[i] as String).NullOr(s => s.Split(','), args[i] as String[]) - .Select(c => - { - DynamicColumn col = DynamicColumn.ParseSelectColumn(c); - if (string.IsNullOrEmpty(col.Aggregate)) - col.Aggregate = agregate; + if (args[i] is string || args[i] is string[]) + builder.SelectColumn((args[i] as String).NullOr(s => s.Split(','), args[i] as String[]) + .Select(c => + { + DynamicColumn col = DynamicColumn.ParseSelectColumn(c); + if (string.IsNullOrEmpty(col.Aggregate)) + col.Aggregate = agregate; - return col; - }).ToArray()); - else if (args[i] is DynamicColumn || args[i] is DynamicColumn[]) - builder.SelectColumn((args[i] as DynamicColumn).NullOr(c => new DynamicColumn[] { c }, args[i] as DynamicColumn[]) - .Select(c => - { - if (string.IsNullOrEmpty(c.Aggregate)) - c.Aggregate = agregate; + return col; + }).ToArray()); + else if (args[i] is DynamicColumn || args[i] is DynamicColumn[]) + builder.SelectColumn((args[i] as DynamicColumn) + .NullOr(c => new DynamicColumn[] { c }, args[i] as DynamicColumn[]) + .Select(c => + { + if (string.IsNullOrEmpty(c.Aggregate)) + c.Aggregate = agregate; - return c; - }).ToArray()); - else goto default; - } + return c; + }).ToArray()); + else goto default; + } break; @@ -6921,7 +7107,7 @@ namespace DynamORM result = (int)(long)result; } else if (op == "Sum" || op == "Max" || - op == "Min" || op == "Avg" || op == "Count") + op == "Min" || op == "Avg" || op == "Count") { if (!builder.HasSelectColumns) throw new InvalidOperationException("You must select one column to agregate."); @@ -6941,9 +7127,11 @@ namespace DynamORM // Be sure to sort by DESC on selected columns if (justOne && !(op == "Last")) { - if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset) + if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == + DynamicDatabaseOptions.SupportLimitOffset) builder.Limit(1); - else if ((Database.Options & DynamicDatabaseOptions.SupportTop) == DynamicDatabaseOptions.SupportTop) + else if ((Database.Options & DynamicDatabaseOptions.SupportTop) == + DynamicDatabaseOptions.SupportTop) builder.Top(1); } @@ -6970,9 +7158,9 @@ namespace DynamORM if (types != null) { if (types.Count == 1) - result = justOne ? - result.Map(types[0]) : - ((IEnumerable)result).MapEnumerable(types[0]); + result = justOne + ? result.Map(types[0]) + : ((IEnumerable)result).MapEnumerable(types[0]); // TODO: Dictionaries } @@ -6982,7 +7170,8 @@ namespace DynamORM return result; } - private void HandleTypeArgument(object[] args, CallInfo info, ref IList types, T builder, int i) where T : DynamicQueryBuilder + private void HandleTypeArgument(object[] args, CallInfo info, ref IList types, T builder, int i) + where T : DynamicQueryBuilder { if (args != null) { @@ -7057,7 +7246,8 @@ namespace DynamORM /// One of the values. /// This action is invoked when transaction is disposed. /// Pass custom transaction parameters. - internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed, object customParams) + internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, + IsolationLevel? il, Action disposed, object customParams) { _db = db; _con = con; @@ -7079,22 +7269,28 @@ namespace DynamORM { if (customParams != null) { - MethodInfo mi = _con.Connection.GetType().GetMethods().Where(m => m.GetParameters().Count() == 1 && m.GetParameters().First().ParameterType == customParams.GetType()).FirstOrDefault(); + MethodInfo 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, })); + _db.TransactionPool[_con.Connection] + .Push((IDbTransaction)mi.Invoke(_con.Connection, new object[] { customParams, })); if (_db.DumpCommands && _db.DumpCommandDelegate != null) _db.DumpCommandDelegate(null, "BEGIN TRAN [CUSTOM ARGS]"); } else - throw new MissingMethodException(string.Format("Method 'BeginTransaction' accepting parameter of type '{0}' in '{1}' not found.", + 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()); + .Push(il.HasValue + ? _con.Connection.BeginTransaction(il.Value) + : _con.Connection.BeginTransaction()); if (_db.DumpCommands && _db.DumpCommandDelegate != null) _db.DumpCommandDelegate(null, "BEGIN TRAN"); @@ -7187,13 +7383,16 @@ namespace DynamORM } /// Gets a value indicating whether this instance is disposed. - public bool IsDisposed { get { return !_isOperational; } } + public bool IsDisposed + { + get { return !_isOperational; } + } #endregion IExtendedDisposable Members } namespace Builders - { + { /// Dynamic delete query builder interface. /// This interface it publicly available. Implementation should be hidden. public interface IDynamicDeleteQueryBuilder : IDynamicQueryBuilder @@ -7201,7 +7400,7 @@ namespace DynamORM /// Execute this builder. /// Result of an execution.. int Execute(); - + /// /// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used @@ -7213,25 +7412,25 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicDeleteQueryBuilder Where(Func func); - + /// Add where condition. /// Condition column with operator and value. /// Builder instance. IDynamicDeleteQueryBuilder Where(DynamicColumn column); - + /// Add where condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. IDynamicDeleteQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value); - + /// Add where condition. /// Condition column. /// Condition value. /// Builder instance. IDynamicDeleteQueryBuilder Where(string column, object value); - + /// Add where condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which @@ -7239,7 +7438,7 @@ namespace DynamORM /// Builder instance. IDynamicDeleteQueryBuilder Where(object conditions, bool schema = false); } - + /// Dynamic insert query builder interface. /// This interface it publicly available. Implementation should be hidden. public interface IDynamicInsertQueryBuilder : IDynamicQueryBuilder @@ -7247,7 +7446,7 @@ namespace DynamORM /// Execute this builder. /// Result of an execution.. int Execute(); - + /// /// Specifies the columns to insert using the dynamic lambda expressions given. Each expression correspond to one /// column, and can: @@ -7258,59 +7457,59 @@ namespace DynamORM /// The specifications. /// This instance to permit chaining. IDynamicInsertQueryBuilder Values(Func fn, params Func[] func); - + /// Add insert fields. /// Insert column. /// Insert value. /// Builder instance. IDynamicInsertQueryBuilder Insert(string column, object value); - + /// Add insert fields. /// Set insert value as properties and values of an object. /// Builder instance. IDynamicInsertQueryBuilder Insert(object o); } - + /// Dynamic query builder base interface. /// This interface it publicly available. Implementation should be hidden. public interface IDynamicQueryBuilder : IExtendedDisposable { /// Gets instance. DynamicDatabase Database { get; } - + /// Gets tables information. IList Tables { get; } - + /// Gets the tables used in this builder. IDictionary Parameters { get; } - + /// Gets or sets a value indicating whether add virtual parameters. bool VirtualMode { get; set; } - + /// Gets a value indicating whether database supports standard schema. bool SupportSchema { get; } - + /// Fill command with query. /// Command to fill. /// Filled instance of . IDbCommand FillCommand(IDbCommand command); - + /// /// Generates the text this command will execute against the underlying database. /// /// The text to execute against the underlying database. /// This method must be override by derived classes. string CommandText(); - + /// Gets or sets the on create temporary parameter actions. /// This is exposed to allow setting schema of column. List> OnCreateTemporaryParameter { get; set; } - + /// Gets or sets the on create real parameter actions. /// This is exposed to allow modification of parameter. List> OnCreateParameter { get; set; } } - + /// Dynamic select query builder interface. /// This interface it publicly available. Implementation should be hidden. public interface IDynamicSelectQueryBuilder : IDynamicQueryBuilder ////, IEnumerable @@ -7318,32 +7517,32 @@ namespace DynamORM /// Execute this builder. /// Enumerator of objects expanded from query. IEnumerable Execute(); - + /// Execute this builder and map to given type. /// Type of object to map on. /// Enumerator of objects expanded from query. IEnumerable Execute() where T : class; - + /// Execute this builder as a data reader. /// Action containing reader. void ExecuteDataReader(Action reader); - + /// Returns a single result. /// Result of a query. object Scalar(); - - #if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE - + +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + /// Returns a single result. /// Type to parse to. /// Default value. /// Result of a query. T ScalarAs(T defaultValue = default(T)); - - #endif - + +#endif + #region From/Join - + /// /// Adds to the 'From' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -7356,7 +7555,7 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder From(Func fn, params Func[] func); - + /// /// Adds to the 'Join' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -7374,11 +7573,11 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder Join(params Func[] func); - + #endregion From/Join - + #region Where - + /// /// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used @@ -7390,36 +7589,36 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder Where(Func func); - + /// Add where condition. /// Condition column with operator and value. /// Builder instance. IDynamicSelectQueryBuilder Where(DynamicColumn column); - + /// Add where condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. IDynamicSelectQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value); - + /// Add where condition. /// Condition column. /// Condition value. /// Builder instance. IDynamicSelectQueryBuilder Where(string column, object value); - + /// Add where condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which /// aren't keys. /// Builder instance. IDynamicSelectQueryBuilder Where(object conditions, bool schema = false); - + #endregion Where - + #region Select - + /// /// Adds to the 'Select' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -7433,23 +7632,23 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder Select(Func fn, params Func[] func); - + /// Add select columns. /// Columns to add to object. /// Builder instance. IDynamicSelectQueryBuilder SelectColumn(params DynamicColumn[] columns); - + /// Add select columns. /// Columns to add to object. /// Column format consist of Column Name, Alias and /// Aggregate function in this order separated by ':'. /// Builder instance. IDynamicSelectQueryBuilder SelectColumn(params string[] columns); - + #endregion Select - + #region GroupBy - + /// /// Adds to the 'Group By' clause the contents obtained from from parsing the dynamic lambda expression given. /// @@ -7457,23 +7656,23 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder GroupBy(Func fn, params Func[] func); - + /// Add select columns. /// Columns to group by. /// Builder instance. IDynamicSelectQueryBuilder GroupByColumn(params DynamicColumn[] columns); - + /// Add select columns. /// Columns to group by. /// Column format consist of Column Name and /// Alias in this order separated by ':'. /// Builder instance. IDynamicSelectQueryBuilder GroupByColumn(params string[] columns); - + #endregion GroupBy - + #region Having - + /// /// Adds to the 'Having' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, Having the specific customs virtual methods supported by the parser are used @@ -7485,36 +7684,36 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder Having(Func func); - + /// Add Having condition. /// Condition column with operator and value. /// Builder instance. IDynamicSelectQueryBuilder Having(DynamicColumn column); - + /// Add Having condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. IDynamicSelectQueryBuilder Having(string column, DynamicColumn.CompareOperator op, object value); - + /// Add Having condition. /// Condition column. /// Condition value. /// Builder instance. IDynamicSelectQueryBuilder Having(string column, object value); - + /// Add Having condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which /// aren't keys. /// Builder instance. IDynamicSelectQueryBuilder Having(object conditions, bool schema = false); - + #endregion Having - + #region OrderBy - + /// /// Adds to the 'Order By' clause the contents obtained from from parsing the dynamic lambda expression given. It /// accepts a multipart column specification followed by an optional Ascending() or Descending() virtual methods @@ -7525,46 +7724,46 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicSelectQueryBuilder OrderBy(Func fn, params Func[] func); - + /// Add select columns. /// Columns to order by. /// Builder instance. IDynamicSelectQueryBuilder OrderByColumn(params DynamicColumn[] columns); - + /// Add select columns. /// Columns to order by. /// Column format consist of Column Name and /// Alias in this order separated by ':'. /// Builder instance. IDynamicSelectQueryBuilder OrderByColumn(params string[] columns); - + #endregion OrderBy - + #region Top/Limit/Offset/Distinct - + /// Set top if database support it. /// How many objects select. /// Builder instance. IDynamicSelectQueryBuilder Top(int? top); - + /// Set top if database support it. /// How many objects select. /// Builder instance. IDynamicSelectQueryBuilder Limit(int? limit); - + /// Set top if database support it. /// How many objects skip selecting. /// Builder instance. IDynamicSelectQueryBuilder Offset(int? offset); - + /// Set distinct mode. /// Distinct mode. /// Builder instance. IDynamicSelectQueryBuilder Distinct(bool distinct = true); - + #endregion Top/Limit/Offset/Distinct } - + /// Dynamic update query builder interface. /// This interface it publicly available. Implementation should be hidden. public interface IDynamicUpdateQueryBuilder : IDynamicQueryBuilder @@ -7572,24 +7771,24 @@ namespace DynamORM /// Execute this builder. /// Result of an execution.. int Execute(); - + #region Update - + /// Add update value or where condition using schema. /// Update or where column name. /// Column value. /// Builder instance. IDynamicUpdateQueryBuilder Update(string column, object value); - + /// Add update values and where condition columns using schema. /// Set values or conditions as properties and values of an object. /// Builder instance. IDynamicUpdateQueryBuilder Update(object conditions); - + #endregion Update - + #region Values - + /// /// Specifies the columns to update using the dynamic lambda expressions given. Each expression correspond to one /// column, and can: @@ -7599,22 +7798,22 @@ namespace DynamORM /// The specifications. /// This instance to permit chaining. IDynamicUpdateQueryBuilder Set(params Func[] func); - + /// Add insert fields. /// Insert column. /// Insert value. /// Builder instance. IDynamicUpdateQueryBuilder Values(string column, object value); - + /// Add insert fields. /// Set insert value as properties and values of an object. /// Builder instance. IDynamicUpdateQueryBuilder Values(object o); - + #endregion Values - + #region Where - + /// /// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used @@ -7626,102 +7825,104 @@ namespace DynamORM /// The specification. /// This instance to permit chaining. IDynamicUpdateQueryBuilder Where(Func func); - + /// Add where condition. /// Condition column with operator and value. /// Builder instance. IDynamicUpdateQueryBuilder Where(DynamicColumn column); - + /// Add where condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. IDynamicUpdateQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value); - + /// Add where condition. /// Condition column. /// Condition value. /// Builder instance. IDynamicUpdateQueryBuilder Where(string column, object value); - + /// Add where condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which /// aren't keys. /// Builder instance. IDynamicUpdateQueryBuilder Where(object conditions, bool schema = false); - + #endregion Where } - + /// Interface describing parameter info. public interface IParameter : IExtendedDisposable { /// Gets the parameter position in command. /// Available after filling the command. int Ordinal { get; } - + /// Gets the parameter temporary name. string Name { get; } - + /// Gets or sets the parameter value. object Value { get; set; } - + /// Gets or sets a value indicating whether name of temporary parameter is well known. bool WellKnown { get; set; } - + /// Gets or sets a value indicating whether this is virtual. bool Virtual { get; set; } - + /// Gets or sets the parameter schema information. DynamicSchemaColumn? Schema { get; set; } } - + /// Interface describing table information. public interface ITableInfo : IExtendedDisposable { /// Gets table owner name. string Owner { get; } - + /// Gets table name. string Name { get; } - + /// Gets table alias. string Alias { get; } - + /// Gets table no lock status. bool NoLock { get; } - + /// Gets table schema. Dictionary Schema { get; } } namespace Extensions - { + { internal static class DynamicHavingQueryExtensions { #region Where - - internal static T InternalHaving(this T builder, Func func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving + + internal static T InternalHaving(this T builder, Func func) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving { return builder.InternalHaving(false, false, func); } - - internal static T InternalHaving(this T builder, bool addBeginBrace, bool addEndBrace, Func func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving + + internal static T InternalHaving(this T builder, bool addBeginBrace, bool addEndBrace, + Func func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving { if (func == null) throw new ArgumentNullException("Array of functions cannot be null."); - + using (DynamicParser parser = DynamicParser.Parse(func)) { string condition = null; bool and = true; - + object result = parser.Result; if (result is string) { condition = (string)result; - + if (condition.ToUpper().IndexOf("OR") == 0) { and = false; @@ -7735,113 +7936,163 @@ namespace DynamORM else { // Intercepting the 'x => x.And()' and 'x => x.Or()' virtual methods... - if (result is DynamicParser.Node.Method && ((DynamicParser.Node.Method)result).Host is DynamicParser.Node.Argument) + if (result is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)result).Host is DynamicParser.Node.Argument) { DynamicParser.Node.Method node = (DynamicParser.Node.Method)result; string name = node.Name.ToUpper(); if (name == "AND" || name == "OR") { object[] args = ((DynamicParser.Node.Method)node).Arguments; - if (args == null) throw new ArgumentNullException("arg", string.Format("{0} is not a parameterless method.", name)); - if (args.Length != 1) throw new ArgumentException(string.Format("{0} requires one and only one parameter: {1}.", name, args.Sketch())); - + if (args == null) + throw new ArgumentNullException("arg", + string.Format("{0} is not a parameterless method.", name)); + if (args.Length != 1) + throw new ArgumentException(string.Format( + "{0} requires one and only one parameter: {1}.", name, args.Sketch())); + and = name == "AND" ? true : false; result = args[0]; } } - + // Just parsing the contents now... condition = builder.Parse(result, pars: builder.Parameters).Validated("Where condition"); } - + if (addBeginBrace) builder.HavingOpenBracketsCount++; if (addEndBrace) builder.HavingOpenBracketsCount--; - + if (builder.HavingCondition == null) builder.HavingCondition = string.Format("{0}{1}{2}", addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty); else - builder.HavingCondition = string.Format("{0} {1} {2}{3}{4}", builder.HavingCondition, and ? "AND" : "OR", + builder.HavingCondition = string.Format("{0} {1} {2}{3}{4}", builder.HavingCondition, + and ? "AND" : "OR", addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty); } - + return builder; } - - internal static T InternalHaving(this T builder, DynamicColumn column) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving + + internal static T InternalHaving(this T builder, DynamicColumn column) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving { bool virt = builder.VirtualMode; if (column.VirtualColumn.HasValue) builder.VirtualMode = column.VirtualColumn.Value; - + Action modParam = (p) => { if (column.Schema.HasValue) p.Schema = column.Schema; - + if (!p.Schema.HasValue) p.Schema = column.Schema ?? builder.GetColumnFromSchema(column.ColumnName); }; - + builder.CreateTemporaryParameterAction(modParam); - + // It's kind of uglu, but... well it works. if (column.Or) switch (column.Operator) { default: - case DynamicColumn.CompareOperator.Eq: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) == column.Value)); break; - case DynamicColumn.CompareOperator.Not: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) != column.Value)); break; - case DynamicColumn.CompareOperator.Like: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Like(column.Value))); break; - case DynamicColumn.CompareOperator.NotLike: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value))); break; - case DynamicColumn.CompareOperator.In: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).In(column.Value))); break; - case DynamicColumn.CompareOperator.Lt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) < column.Value)); break; - case DynamicColumn.CompareOperator.Lte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) <= column.Value)); break; - case DynamicColumn.CompareOperator.Gt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) > column.Value)); break; - case DynamicColumn.CompareOperator.Gte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) >= column.Value)); break; - case DynamicColumn.CompareOperator.Between: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Between(column.Value))); break; + case DynamicColumn.CompareOperator.Eq: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) == column.Value)); break; + case DynamicColumn.CompareOperator.Not: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) != column.Value)); break; + case DynamicColumn.CompareOperator.Like: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).Like(column.Value))); break; + case DynamicColumn.CompareOperator.NotLike: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value))); + break; + case DynamicColumn.CompareOperator.In: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).In(column.Value))); break; + case DynamicColumn.CompareOperator.Lt: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) < column.Value)); break; + case DynamicColumn.CompareOperator.Lte: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) <= column.Value)); break; + case DynamicColumn.CompareOperator.Gt: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) > column.Value)); break; + case DynamicColumn.CompareOperator.Gte: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) >= column.Value)); break; + case DynamicColumn.CompareOperator.Between: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).Between(column.Value))); + break; } else switch (column.Operator) { default: - case DynamicColumn.CompareOperator.Eq: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) == column.Value); break; - case DynamicColumn.CompareOperator.Not: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) != column.Value); break; - case DynamicColumn.CompareOperator.Like: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Like(column.Value)); break; - case DynamicColumn.CompareOperator.NotLike: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value)); break; - case DynamicColumn.CompareOperator.In: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).In(column.Value)); break; - case DynamicColumn.CompareOperator.Lt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) < column.Value); break; - case DynamicColumn.CompareOperator.Lte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) <= column.Value); break; - case DynamicColumn.CompareOperator.Gt: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) > column.Value); break; - case DynamicColumn.CompareOperator.Gte: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) >= column.Value); break; - case DynamicColumn.CompareOperator.Between: builder.InternalHaving(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Between(column.Value)); break; + case DynamicColumn.CompareOperator.Eq: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) == column.Value); break; + case DynamicColumn.CompareOperator.Not: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) != column.Value); break; + case DynamicColumn.CompareOperator.Like: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).Like(column.Value)); break; + case DynamicColumn.CompareOperator.NotLike: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value)); break; + case DynamicColumn.CompareOperator.In: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).In(column.Value)); break; + case DynamicColumn.CompareOperator.Lt: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) < column.Value); break; + case DynamicColumn.CompareOperator.Lte: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) <= column.Value); break; + case DynamicColumn.CompareOperator.Gt: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) > column.Value); break; + case DynamicColumn.CompareOperator.Gte: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) >= column.Value); break; + case DynamicColumn.CompareOperator.Between: + builder.InternalHaving(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).Between(column.Value)); break; } - + builder.OnCreateTemporaryParameter.Remove(modParam); builder.VirtualMode = virt; - + return builder; } - - internal static T InternalHaving(this T builder, string column, DynamicColumn.CompareOperator op, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving + + internal static T InternalHaving(this T builder, string column, DynamicColumn.CompareOperator op, + object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving { if (value is DynamicColumn) { DynamicColumn v = (DynamicColumn)value; - + if (string.IsNullOrEmpty(v.ColumnName)) v.ColumnName = column; - + return builder.InternalHaving(v); } else if (value is IEnumerable) { foreach (DynamicColumn v in (IEnumerable)value) builder.InternalHaving(v); - + return builder; } - + return builder.InternalHaving(new DynamicColumn { ColumnName = column, @@ -7849,13 +8100,15 @@ namespace DynamORM Value = value }); } - - internal static T InternalHaving(this T builder, string column, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving + + internal static T InternalHaving(this T builder, string column, object value) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving { return builder.InternalHaving(column, DynamicColumn.CompareOperator.Eq, value); } - - internal static T InternalHaving(this T builder, object conditions, bool schema = false) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving + + internal static T InternalHaving(this T builder, object conditions, bool schema = false) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithHaving { if (conditions is DynamicColumn) return builder.InternalHaving((DynamicColumn)conditions); @@ -7863,58 +8116,62 @@ namespace DynamORM { foreach (DynamicColumn v in (IEnumerable)conditions) builder.InternalHaving(v); - + return builder; } - + IDictionary dict = conditions.ToDictionary(); DynamicTypeMap mapper = DynamicMapperCache.GetMapper(conditions.GetType()); string table = dict.TryGetValue("_table").NullOr(x => x.ToString(), string.Empty); - + foreach (KeyValuePair condition in dict) { if (mapper.Ignored.Contains(condition.Key) || condition.Key == "_table") continue; - - string colName = mapper != null ? mapper.PropertyMap.TryGetValue(condition.Key) ?? condition.Key : condition.Key; - + + string colName = mapper != null + ? mapper.PropertyMap.TryGetValue(condition.Key) ?? condition.Key + : condition.Key; + DynamicSchemaColumn? col = null; - + // This should be used on typed queries or update/delete steatements, which usualy operate on a single table. if (schema) { col = builder.GetColumnFromSchema(colName, mapper, table); - + if ((!col.HasValue || !col.Value.IsKey) && - (mapper == null || mapper.ColumnsMap.TryGetValue(colName).NullOr(m => m.Ignore || m.Column.NullOr(c => !c.IsKey, true), true))) + (mapper == null || mapper.ColumnsMap.TryGetValue(colName) + .NullOr(m => m.Ignore || m.Column.NullOr(c => !c.IsKey, true), true))) continue; - + colName = col.HasValue ? col.Value.Name : colName; } - + if (!string.IsNullOrEmpty(table)) - builder.InternalHaving(x => x(builder.FixObjectName(string.Format("{0}.{1}", table, colName))) == condition.Value); + builder.InternalHaving(x => + x(builder.FixObjectName(string.Format("{0}.{1}", table, colName))) == condition.Value); else builder.InternalHaving(x => x(builder.FixObjectName(colName)) == condition.Value); } - + return builder; } - + #endregion Where } - + internal static class DynamicModifyBuilderExtensions { internal static T Table(this T builder, Func func) where T : DynamicModifyBuilder { if (func == null) throw new ArgumentNullException("Function cannot be null."); - + using (DynamicParser parser = DynamicParser.Parse(func)) { object result = parser.Result; - + // If the expression result is string. if (result is string) return builder.Table((string)result); @@ -7924,95 +8181,110 @@ namespace DynamORM { // Or if it resolves to a dynamic node DynamicParser.Node node = (DynamicParser.Node)result; - + string owner = null; string main = null; - + while (true) { // Deny support for the AS() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") - throw new ArgumentException(string.Format("Alias is not supported on modification builders. (Parsing: {0})", result)); - + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") + throw new ArgumentException(string.Format( + "Alias is not supported on modification builders. (Parsing: {0})", result)); + // Support for table specifications... if (node is DynamicParser.Node.GetMember) { if (owner != null) - throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); - + throw new ArgumentException(string.Format( + "Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); + if (main != null) owner = ((DynamicParser.Node.GetMember)node).Name; else main = ((DynamicParser.Node.GetMember)node).Name; - + node = node.Host; continue; } - + // Support for generic sources... if (node is DynamicParser.Node.Invoke) { if (owner == null && main == null) { DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node; - + if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is Type) return builder.Table((Type)invoke.Arguments[0]); else if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is String) return builder.Table((string)invoke.Arguments[0]); else - throw new ArgumentException(string.Format("Invalid argument count or type when parsing '{2}'. Invoke supports only one argument of type Type or String", owner, main, result)); + throw new ArgumentException(string.Format( + "Invalid argument count or type when parsing '{2}'. Invoke supports only one argument of type Type or String", + owner, main, result)); } else if (owner != null) - throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); + throw new ArgumentException(string.Format( + "Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); else if (main != null) - throw new ArgumentException(string.Format("Main '{0}' is already set when parsing '{1}'.", main, result)); + throw new ArgumentException( + string.Format("Main '{0}' is already set when parsing '{1}'.", main, + result)); } - + if (!string.IsNullOrEmpty(main)) return builder.Table(string.Format("{0}{1}", string.IsNullOrEmpty(owner) ? string.Empty : string.Format("{0}.", owner), main)); } } - + throw new ArgumentException(string.Format("Unable to set table parsing '{0}'", result)); } } - - internal static T Table(this T builder, string tableName, Dictionary schema = null) where T : DynamicModifyBuilder + + internal static T Table(this T builder, string tableName, + Dictionary schema = null) where T : DynamicModifyBuilder { Tuple tuple = tableName.Validated("Table Name").SplitSomethingAndAlias(); - + if (!string.IsNullOrEmpty(tuple.Item2)) - throw new ArgumentException(string.Format("Can not use aliases in INSERT steatement. ({0})", tableName), "tableName"); - + throw new ArgumentException( + string.Format("Can not use aliases in INSERT steatement. ({0})", tableName), "tableName"); + string[] parts = tuple.Item1.Split('.'); - + if (parts.Length > 2) - throw new ArgumentException(string.Format("Table name can consist only from name or owner and name. ({0})", tableName), "tableName"); - + throw new ArgumentException( + string.Format("Table name can consist only from name or owner and name. ({0})", tableName), + "tableName"); + builder.Tables.Clear(); builder.Tables.Add(new DynamicQueryBuilder.TableInfo(builder.Database, - builder.Database.StripName(parts.Last()).Validated("Table"), null, - parts.Length == 2 ? builder.Database.StripName(parts.First()).Validated("Owner", canbeNull: true) : null)); - + builder.Database.StripName(parts.Last()).Validated("Table"), null, + parts.Length == 2 + ? builder.Database.StripName(parts.First()).Validated("Owner", canbeNull: true) + : null)); + if (schema != null) (builder.Tables[0] as DynamicQueryBuilder.TableInfo).Schema = schema; - + return builder; } - + internal static T Table(this T builder, Type type) where T : DynamicQueryBuilder { if (type.IsAnonymous()) - throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}).", type.FullName)); - + throw new InvalidOperationException( + string.Format("Cant assign anonymous type as a table ({0}).", type.FullName)); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); - + if (mapper == null) throw new InvalidOperationException("Cant assign unmapable type as a table."); - + if (builder is DynamicModifyBuilder) { builder.Tables.Clear(); @@ -8020,34 +8292,36 @@ namespace DynamORM } else if (builder is DynamicSelectQueryBuilder) (builder as DynamicSelectQueryBuilder).From(x => x(type)); - + return builder; } } - + internal static class DynamicWhereQueryExtensions { #region Where - - internal static T InternalWhere(this T builder, Func func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + + internal static T InternalWhere(this T builder, Func func) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere { return builder.InternalWhere(false, false, func); } - - internal static T InternalWhere(this T builder, bool addBeginBrace, bool addEndBrace, Func func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + + internal static T InternalWhere(this T builder, bool addBeginBrace, bool addEndBrace, + Func func) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere { if (func == null) throw new ArgumentNullException("Array of functions cannot be null."); - + using (DynamicParser parser = DynamicParser.Parse(func)) { string condition = null; bool and = true; - + object result = parser.Result; if (result is string) { condition = (string)result; - + if (condition.ToUpper().IndexOf("OR") == 0) { and = false; @@ -8061,113 +8335,163 @@ namespace DynamORM else { // Intercepting the 'x => x.And()' and 'x => x.Or()' virtual methods... - if (result is DynamicParser.Node.Method && ((DynamicParser.Node.Method)result).Host is DynamicParser.Node.Argument) + if (result is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)result).Host is DynamicParser.Node.Argument) { DynamicParser.Node.Method node = (DynamicParser.Node.Method)result; string name = node.Name.ToUpper(); if (name == "AND" || name == "OR") { object[] args = ((DynamicParser.Node.Method)node).Arguments; - if (args == null) throw new ArgumentNullException("arg", string.Format("{0} is not a parameterless method.", name)); - if (args.Length != 1) throw new ArgumentException(string.Format("{0} requires one and only one parameter: {1}.", name, args.Sketch())); - + if (args == null) + throw new ArgumentNullException("arg", + string.Format("{0} is not a parameterless method.", name)); + if (args.Length != 1) + throw new ArgumentException(string.Format( + "{0} requires one and only one parameter: {1}.", name, args.Sketch())); + and = name == "AND" ? true : false; result = args[0]; } } - + // Just parsing the contents now... condition = builder.Parse(result, pars: builder.Parameters).Validated("Where condition"); } - + if (addBeginBrace) builder.WhereOpenBracketsCount++; if (addEndBrace) builder.WhereOpenBracketsCount--; - + if (builder.WhereCondition == null) builder.WhereCondition = string.Format("{0}{1}{2}", addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty); else - builder.WhereCondition = string.Format("{0} {1} {2}{3}{4}", builder.WhereCondition, and ? "AND" : "OR", + builder.WhereCondition = string.Format("{0} {1} {2}{3}{4}", builder.WhereCondition, + and ? "AND" : "OR", addBeginBrace ? "(" : string.Empty, condition, addEndBrace ? ")" : string.Empty); } - + return builder; } - - internal static T InternalWhere(this T builder, DynamicColumn column) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + + internal static T InternalWhere(this T builder, DynamicColumn column) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere { bool virt = builder.VirtualMode; if (column.VirtualColumn.HasValue) builder.VirtualMode = column.VirtualColumn.Value; - + Action modParam = (p) => { if (column.Schema.HasValue) p.Schema = column.Schema; - + if (!p.Schema.HasValue) p.Schema = column.Schema ?? builder.GetColumnFromSchema(column.ColumnName); }; - + builder.CreateTemporaryParameterAction(modParam); - + // It's kind of uglu, but... well it works. if (column.Or) switch (column.Operator) { default: - case DynamicColumn.CompareOperator.Eq: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) == column.Value)); break; - case DynamicColumn.CompareOperator.Not: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) != column.Value)); break; - case DynamicColumn.CompareOperator.Like: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Like(column.Value))); break; - case DynamicColumn.CompareOperator.NotLike: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value))); break; - case DynamicColumn.CompareOperator.In: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).In(column.Value))); break; - case DynamicColumn.CompareOperator.Lt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) < column.Value)); break; - case DynamicColumn.CompareOperator.Lte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) <= column.Value)); break; - case DynamicColumn.CompareOperator.Gt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) > column.Value)); break; - case DynamicColumn.CompareOperator.Gte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)) >= column.Value)); break; - case DynamicColumn.CompareOperator.Between: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x.Or(x(builder.FixObjectName(column.ColumnName)).Between(column.Value))); break; + case DynamicColumn.CompareOperator.Eq: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) == column.Value)); break; + case DynamicColumn.CompareOperator.Not: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) != column.Value)); break; + case DynamicColumn.CompareOperator.Like: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).Like(column.Value))); break; + case DynamicColumn.CompareOperator.NotLike: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value))); + break; + case DynamicColumn.CompareOperator.In: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).In(column.Value))); break; + case DynamicColumn.CompareOperator.Lt: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) < column.Value)); break; + case DynamicColumn.CompareOperator.Lte: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) <= column.Value)); break; + case DynamicColumn.CompareOperator.Gt: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) > column.Value)); break; + case DynamicColumn.CompareOperator.Gte: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)) >= column.Value)); break; + case DynamicColumn.CompareOperator.Between: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x.Or(x(builder.FixObjectName(column.ColumnName)).Between(column.Value))); + break; } else switch (column.Operator) { default: - case DynamicColumn.CompareOperator.Eq: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) == column.Value); break; - case DynamicColumn.CompareOperator.Not: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) != column.Value); break; - case DynamicColumn.CompareOperator.Like: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Like(column.Value)); break; - case DynamicColumn.CompareOperator.NotLike: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value)); break; - case DynamicColumn.CompareOperator.In: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).In(column.Value)); break; - case DynamicColumn.CompareOperator.Lt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) < column.Value); break; - case DynamicColumn.CompareOperator.Lte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) <= column.Value); break; - case DynamicColumn.CompareOperator.Gt: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) > column.Value); break; - case DynamicColumn.CompareOperator.Gte: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)) >= column.Value); break; - case DynamicColumn.CompareOperator.Between: builder.InternalWhere(column.BeginBlock, column.EndBlock, x => x(builder.FixObjectName(column.ColumnName)).Between(column.Value)); break; + case DynamicColumn.CompareOperator.Eq: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) == column.Value); break; + case DynamicColumn.CompareOperator.Not: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) != column.Value); break; + case DynamicColumn.CompareOperator.Like: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).Like(column.Value)); break; + case DynamicColumn.CompareOperator.NotLike: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).NotLike(column.Value)); break; + case DynamicColumn.CompareOperator.In: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).In(column.Value)); break; + case DynamicColumn.CompareOperator.Lt: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) < column.Value); break; + case DynamicColumn.CompareOperator.Lte: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) <= column.Value); break; + case DynamicColumn.CompareOperator.Gt: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) > column.Value); break; + case DynamicColumn.CompareOperator.Gte: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)) >= column.Value); break; + case DynamicColumn.CompareOperator.Between: + builder.InternalWhere(column.BeginBlock, column.EndBlock, + x => x(builder.FixObjectName(column.ColumnName)).Between(column.Value)); break; } - + builder.OnCreateTemporaryParameter.Remove(modParam); builder.VirtualMode = virt; - + return builder; } - - internal static T InternalWhere(this T builder, string column, DynamicColumn.CompareOperator op, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + + internal static T InternalWhere(this T builder, string column, DynamicColumn.CompareOperator op, + object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere { if (value is DynamicColumn) { DynamicColumn v = (DynamicColumn)value; - + if (string.IsNullOrEmpty(v.ColumnName)) v.ColumnName = column; - + return builder.InternalWhere(v); } else if (value is IEnumerable) { foreach (DynamicColumn v in (IEnumerable)value) builder.InternalWhere(v); - + return builder; } - + return builder.InternalWhere(new DynamicColumn { ColumnName = column, @@ -8175,13 +8499,15 @@ namespace DynamORM Value = value }); } - - internal static T InternalWhere(this T builder, string column, object value) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + + internal static T InternalWhere(this T builder, string column, object value) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere { return builder.InternalWhere(column, DynamicColumn.CompareOperator.Eq, value); } - - internal static T InternalWhere(this T builder, object conditions, bool schema = false) where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + + internal static T InternalWhere(this T builder, object conditions, bool schema = false) + where T : DynamicQueryBuilder, DynamicQueryBuilder.IQueryWithWhere { if (conditions is DynamicColumn) return builder.InternalWhere((DynamicColumn)conditions); @@ -8189,52 +8515,57 @@ namespace DynamORM { foreach (DynamicColumn v in (IEnumerable)conditions) builder.InternalWhere(v); - + return builder; } - + IDictionary dict = conditions.ToDictionary(); DynamicTypeMap mapper = DynamicMapperCache.GetMapper(conditions.GetType()); string table = dict.TryGetValue("_table").NullOr(x => x.ToString(), string.Empty); - + foreach (KeyValuePair condition in dict) { if (mapper.Ignored.Contains(condition.Key) || condition.Key == "_table") continue; - - string colName = mapper != null ? mapper.PropertyMap.TryGetValue(condition.Key) ?? condition.Key : condition.Key; - + + string colName = mapper != null + ? mapper.PropertyMap.TryGetValue(condition.Key) ?? condition.Key + : condition.Key; + DynamicSchemaColumn? col = null; - + // This should be used on typed queries or update/delete steatements, which usualy operate on a single table. if (schema) { col = builder.GetColumnFromSchema(colName, mapper, table); - + if ((!col.HasValue || !col.Value.IsKey) && - (mapper == null || mapper.ColumnsMap.TryGetValue(colName).NullOr(m => m.Ignore || m.Column.NullOr(c => !c.IsKey, true), true))) + (mapper == null || mapper.ColumnsMap.TryGetValue(colName) + .NullOr(m => m.Ignore || m.Column.NullOr(c => !c.IsKey, true), true))) continue; - + colName = col.HasValue ? col.Value.Name : colName; } - + if (!string.IsNullOrEmpty(table)) - builder.InternalWhere(x => x(builder.FixObjectName(string.Format("{0}.{1}", table, colName))) == condition.Value); + builder.InternalWhere(x => + x(builder.FixObjectName(string.Format("{0}.{1}", table, colName))) == condition.Value); else builder.InternalWhere(x => x(builder.FixObjectName(colName)) == condition.Value); } - + return builder; } - + #endregion Where } } namespace Implementation - { + { /// Implementation of dynamic delete query builder. - internal class DynamicDeleteQueryBuilder : DynamicModifyBuilder, IDynamicDeleteQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + internal class DynamicDeleteQueryBuilder : DynamicModifyBuilder, IDynamicDeleteQueryBuilder, + DynamicQueryBuilder.IQueryWithWhere { /// /// Initializes a new instance of the class. @@ -8244,7 +8575,7 @@ namespace DynamORM : base(db) { } - + /// /// Initializes a new instance of the class. /// @@ -8254,7 +8585,7 @@ namespace DynamORM : base(db, tableName) { } - + /// Generates the text this command will execute against the underlying database. /// The text to execute against the underlying database. /// This method must be override by derived classes. @@ -8262,14 +8593,16 @@ namespace DynamORM { ITableInfo info = Tables.Single(); return string.Format("DELETE FROM {0}{1}{2}{3}", - string.IsNullOrEmpty(info.Owner) ? string.Empty : string.Format("{0}.", Database.DecorateName(info.Owner)), + string.IsNullOrEmpty(info.Owner) + ? string.Empty + : string.Format("{0}.", Database.DecorateName(info.Owner)), Database.DecorateName(info.Name), string.IsNullOrEmpty(WhereCondition) ? string.Empty : " WHERE ", WhereCondition); } - + #region Where - + /// /// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used @@ -8284,7 +8617,7 @@ namespace DynamORM { return this.InternalWhere(func); } - + /// Add where condition. /// Condition column with operator and value. /// Builder instance. @@ -8292,17 +8625,18 @@ namespace DynamORM { return this.InternalWhere(column); } - + /// Add where condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. - public virtual IDynamicDeleteQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value) + public virtual IDynamicDeleteQueryBuilder Where(string column, DynamicColumn.CompareOperator op, + object value) { return this.InternalWhere(column, op, value); } - + /// Add where condition. /// Condition column. /// Condition value. @@ -8311,7 +8645,7 @@ namespace DynamORM { return this.InternalWhere(column, value); } - + /// Add where condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which @@ -8321,16 +8655,16 @@ namespace DynamORM { return this.InternalWhere(conditions, schema); } - + #endregion Where } - + /// Implementation of dynamic insert query builder. internal class DynamicInsertQueryBuilder : DynamicModifyBuilder, IDynamicInsertQueryBuilder { private string _columns; private string _values; - + /// /// Initializes a new instance of the class. /// @@ -8339,7 +8673,7 @@ namespace DynamORM : base(db) { } - + /// /// Initializes a new instance of the class. /// @@ -8349,7 +8683,7 @@ namespace DynamORM : base(db, tableName) { } - + /// Generates the text this command will execute against the underlying database. /// The text to execute against the underlying database. /// This method must be override by derived classes. @@ -8357,12 +8691,14 @@ namespace DynamORM { ITableInfo info = Tables.Single(); return string.Format("INSERT INTO {0}{1} ({2}) VALUES ({3})", - string.IsNullOrEmpty(info.Owner) ? string.Empty : string.Format("{0}.", Database.DecorateName(info.Owner)), + string.IsNullOrEmpty(info.Owner) + ? string.Empty + : string.Format("{0}.", Database.DecorateName(info.Owner)), Database.DecorateName(info.Name), _columns, _values); } - + #region Insert - + /// /// Specifies the columns to insert using the dynamic lambda expressions given. Each expression correspond to one /// column, and can: @@ -8372,46 +8708,47 @@ namespace DynamORM /// The specifications. /// The specifications. /// This instance to permit chaining. - public virtual IDynamicInsertQueryBuilder Values(Func fn, params Func[] func) + public virtual IDynamicInsertQueryBuilder Values(Func fn, + params Func[] func) { if (fn == null) throw new ArgumentNullException("Array of specifications cannot be null."); - + int index = InsertFunc(-1, fn); - + if (func != null) foreach (Func f in func) index = InsertFunc(index, f); - + return this; } - + private int InsertFunc(int index, Func f) { index++; - + if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - + string main = null; string value = null; string str = null; - + // When 'x => x.Table.Column = value' or 'x => x.Column = value'... if (result is DynamicParser.Node.SetMember) { DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result; - + DynamicSchemaColumn? col = GetColumnFromSchema(node.Name); main = Database.DecorateName(node.Name); value = Parse(node.Value, ref col, pars: Parameters, nulls: true); - + _columns = _columns == null ? main : string.Format("{0}, {1}", _columns, main); _values = _values == null ? value : string.Format("{0}, {1}", _values, value); return index; @@ -8421,7 +8758,7 @@ namespace DynamORM Insert(result); return index; } - + // Other specifications are considered invalid... string err = string.Format("Specification '{0}' is invalid.", result); str = Parse(result); @@ -8429,7 +8766,7 @@ namespace DynamORM throw new ArgumentException(err); } } - + /// Add insert fields. /// Insert column. /// Insert value. @@ -8439,20 +8776,20 @@ namespace DynamORM if (value is DynamicColumn) { DynamicColumn v = (DynamicColumn)value; - + if (string.IsNullOrEmpty(v.ColumnName)) v.ColumnName = column; - + return Insert(v); } - + return Insert(new DynamicColumn { ColumnName = column, Value = value, }); } - + /// Add insert fields. /// Set insert value as properties and values of an object. /// Builder instance. @@ -8462,19 +8799,19 @@ namespace DynamORM { DynamicColumn column = (DynamicColumn)o; DynamicSchemaColumn? col = column.Schema ?? GetColumnFromSchema(column.ColumnName); - + string main = FixObjectName(column.ColumnName, onlyColumn: true); string value = Parse(column.Value, ref col, pars: Parameters, nulls: true); - + _columns = _columns == null ? main : string.Format("{0}, {1}", _columns, main); _values = _values == null ? value : string.Format("{0}, {1}", _values, value); - + return this; } - + IDictionary dict = o.ToDictionary(); DynamicTypeMap mapper = DynamicMapperCache.GetMapper(o.GetType()); - + if (mapper != null) { foreach (KeyValuePair con in dict) @@ -8482,7 +8819,7 @@ namespace DynamORM { string colName = mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key; DynamicPropertyInvoker propMap = mapper.ColumnsMap.TryGetValue(colName.ToLower()); - + if (propMap == null || propMap.Column == null || !propMap.Column.IsNoInsert) Insert(colName, con.Value); // TODO: This probably should get value from mapper } @@ -8490,26 +8827,26 @@ namespace DynamORM else foreach (KeyValuePair con in dict) Insert(con.Key, con.Value); - + return this; } - + #endregion Insert - + #region IExtendedDisposable - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public override void Dispose() { base.Dispose(); - + _columns = _values = null; } - + #endregion IExtendedDisposable } - + /// Base query builder for insert/update/delete statements. internal abstract class DynamicModifyBuilder : DynamicQueryBuilder { @@ -8522,7 +8859,7 @@ namespace DynamORM { VirtualMode = false; } - + /// /// Initializes a new instance of the class. /// @@ -8534,7 +8871,7 @@ namespace DynamORM VirtualMode = false; this.Table(tableName); } - + /// Execute this builder. /// Result of an execution.. public virtual int Execute() @@ -8548,7 +8885,7 @@ namespace DynamORM } } } - + /// Implementation of dynamic query builder base interface. internal abstract class DynamicQueryBuilder : IDynamicQueryBuilder { @@ -8557,25 +8894,25 @@ namespace DynamORM { /// Gets or sets the where condition. string WhereCondition { get; set; } - + /// Gets or sets the amount of not closed brackets in where statement. int WhereOpenBracketsCount { get; set; } } - + /// Empty interface to allow having query builder implementation use universal approach. internal interface IQueryWithHaving { /// Gets or sets the having condition. string HavingCondition { get; set; } - + /// Gets or sets the amount of not closed brackets in having statement. int HavingOpenBracketsCount { get; set; } } - + private DynamicQueryBuilder _parent = null; - + #region TableInfo - + /// Table information. internal class TableInfo : ITableInfo { @@ -8586,7 +8923,7 @@ namespace DynamORM { IsDisposed = false; } - + /// /// Initializes a new instance of the class. /// @@ -8595,18 +8932,19 @@ namespace DynamORM /// The table alias. /// The table owner. /// The table should be used with nolock. - public TableInfo(DynamicDatabase db, string name, string alias = null, string owner = null, bool nolock = false) + public TableInfo(DynamicDatabase db, string name, string alias = null, string owner = null, + bool nolock = false) : this() { Name = name; Alias = alias; Owner = owner; NoLock = nolock; - + if (!name.ContainsAny(StringExtensions.InvalidMemberChars)) Schema = db.GetSchema(name, owner: owner); } - + /// /// Initializes a new instance of the class. /// @@ -8615,53 +8953,55 @@ namespace DynamORM /// The table alias. /// The table owner. /// The table should be used with nolock. - public TableInfo(DynamicDatabase db, Type type, string alias = null, string owner = null, bool nolock = false) + public TableInfo(DynamicDatabase db, Type type, string alias = null, string owner = null, + bool nolock = false) : this() { DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); - - Name = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - mapper.Type.Name : mapper.Table.Name; - + + Name = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) + ? mapper.Type.Name + : mapper.Table.Name; + Owner = (mapper.Table != null) ? mapper.Table.Owner : owner; Alias = alias; NoLock = nolock; - + Schema = db.GetSchema(type); } - + /// Gets or sets table owner name. public string Owner { get; internal set; } - + /// Gets or sets table name. public string Name { get; internal set; } - + /// Gets or sets table alias. public string Alias { get; internal set; } - + /// Gets or sets table alias. public bool NoLock { get; internal set; } - + /// Gets or sets table schema. public Dictionary Schema { get; internal set; } - + /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public virtual void Dispose() { IsDisposed = true; - + ////if (Schema != null) //// Schema.Clear(); - + Owner = Name = Alias = null; Schema = null; } } - + /// Generic based table information. /// Type of class that is represented in database. internal class TableInfo : TableInfo @@ -8677,11 +9017,11 @@ namespace DynamORM { } } - + #endregion TableInfo - + #region Parameter - + /// Interface describing parameter info. internal class Parameter : IParameter { @@ -8691,44 +9031,44 @@ namespace DynamORM { IsDisposed = false; } - + /// Gets or sets the parameter position in command. /// Available after filling the command. public int Ordinal { get; internal set; } - + /// Gets or sets the parameter temporary name. public string Name { get; internal set; } - + /// Gets or sets the parameter value. public object Value { get; set; } - + /// Gets or sets a value indicating whether name of temporary parameter is well known. public bool WellKnown { get; set; } - + /// Gets or sets a value indicating whether this is virtual. public bool Virtual { get; set; } - + /// Gets or sets the parameter schema information. public DynamicSchemaColumn? Schema { get; set; } - + /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public virtual void Dispose() { IsDisposed = true; - + Name = null; Schema = null; } } - + #endregion Parameter - + #region Constructor - + /// /// Initializes a new instance of the class. /// @@ -8741,18 +9081,20 @@ namespace DynamORM Parameters = new Dictionary(); OnCreateTemporaryParameter = new List>(); OnCreateParameter = new List>(); - + WhereCondition = null; WhereOpenBracketsCount = 0; - + Database = db; if (Database != null) Database.AddToCache(this); - - SupportSchema = (db.Options & DynamicDatabaseOptions.SupportSchema) == DynamicDatabaseOptions.SupportSchema; - SupportNoLock = (db.Options & DynamicDatabaseOptions.SupportNoLock) == DynamicDatabaseOptions.SupportNoLock; + + SupportSchema = (db.Options & DynamicDatabaseOptions.SupportSchema) == + DynamicDatabaseOptions.SupportSchema; + SupportNoLock = (db.Options & DynamicDatabaseOptions.SupportNoLock) == + DynamicDatabaseOptions.SupportNoLock; } - + /// Initializes a new instance of the class. /// The database. /// The parent query. @@ -8761,54 +9103,54 @@ namespace DynamORM { _parent = parent; } - + #endregion Constructor - + #region IQueryWithWhere - + /// Gets or sets the where condition. public string WhereCondition { get; set; } - + /// Gets or sets the amount of not closed brackets in where statement. public int WhereOpenBracketsCount { get; set; } - + #endregion IQueryWithWhere - + #region IDynamicQueryBuilder - + /// Gets instance. public DynamicDatabase Database { get; private set; } - + /// Gets the tables used in this builder. public IList Tables { get; private set; } - + /// Gets the tables used in this builder. public IDictionary Parameters { get; private set; } - + /// Gets or sets a value indicating whether add virtual parameters. public bool VirtualMode { get; set; } - + /// Gets or sets the on create temporary parameter actions. /// This is exposed to allow setting schema of column. public List> OnCreateTemporaryParameter { get; set; } - + /// Gets or sets the on create real parameter actions. /// This is exposed to allow modification of parameter. public List> OnCreateParameter { get; set; } - + /// Gets a value indicating whether database supports standard schema. public bool SupportSchema { get; private set; } - + /// Gets a value indicating whether database supports with no lock syntax. public bool SupportNoLock { get; private set; } - + /// /// Generates the text this command will execute against the underlying database. /// /// The text to execute against the underlying database. /// This method must be override by derived classes. public abstract string CommandText(); - + /// Fill command with query. /// Command to fill. /// Filled instance of . @@ -8823,19 +9165,19 @@ namespace DynamORM WhereOpenBracketsCount--; } } - + // End not ended having statement if (this is IQueryWithHaving) { IQueryWithHaving h = this as IQueryWithHaving; - + while (h.HavingOpenBracketsCount > 0) { h.HavingCondition += ")"; h.HavingOpenBracketsCount--; } } - + return command.SetCommand(CommandText() .FillStringWithVariables(s => { @@ -8844,21 +9186,21 @@ namespace DynamORM IDbDataParameter param = (IDbDataParameter)command .AddParameter(this, p.Schema, p.Value) .Parameters[command.Parameters.Count - 1]; - + (p as Parameter).Ordinal = command.Parameters.Count - 1; - + if (OnCreateParameter != null) OnCreateParameter.ForEach(x => x(p, param)); - + return param.ParameterName; }, s); })); } - + #endregion IDynamicQueryBuilder - + #region Parser - + /// Parses the arbitrary object given and translates it into a string with the appropriate /// syntax for the database this parser is specific to. /// The object to parse and translate. It can be any arbitrary object, including null values (if @@ -8873,13 +9215,14 @@ namespace DynamORM /// A string containing the result of the parsing, along with the parameters extracted in the /// instance if such is given. /// Null nodes are not accepted. - internal virtual string Parse(object node, IDictionary pars = null, bool rawstr = false, bool nulls = false, bool decorate = true, bool isMultiPart = true) + internal virtual string Parse(object node, IDictionary pars = null, + bool rawstr = false, bool nulls = false, bool decorate = true, bool isMultiPart = true) { DynamicSchemaColumn? c = null; - + return Parse(node, ref c, pars, rawstr, nulls, decorate, isMultiPart); } - + /// Parses the arbitrary object given and translates it into a string with the appropriate /// syntax for the database this parser is specific to. /// The object to parse and translate. It can be any arbitrary object, including null values (if @@ -8895,92 +9238,110 @@ namespace DynamORM /// A string containing the result of the parsing, along with the parameters extracted in the /// instance if such is given. /// Null nodes are not accepted. - internal virtual string Parse(object node, ref DynamicSchemaColumn? columnSchema, IDictionary pars = null, bool rawstr = false, bool nulls = false, bool decorate = true, bool isMultiPart = true) + internal virtual string Parse(object node, ref DynamicSchemaColumn? columnSchema, + IDictionary pars = null, bool rawstr = false, bool nulls = false, + bool decorate = true, bool isMultiPart = true) { // Null nodes are accepted or not depending upon the "nulls" flag... if (node == null) { if (!nulls) throw new ArgumentNullException("node", "Null nodes are not accepted."); - + return Dispatch(node, ref columnSchema, pars, decorate); } - + // Nodes that are strings are parametrized or not depending the "rawstr" flag... if (node is string) { if (rawstr) return (string)node; else return Dispatch(node, ref columnSchema, pars, decorate); } - + // If node is a delegate, parse it to create the logical tree... if (node is Delegate) { using (DynamicParser p = DynamicParser.Parse((Delegate)node)) { node = p.Result; - - return Parse(node, ref columnSchema, pars, rawstr, decorate: decorate); // Intercept containers as in (x => "string") + + return Parse(node, ref columnSchema, pars, rawstr, + decorate: decorate); // Intercept containers as in (x => "string") } } - + return Dispatch(node, ref columnSchema, pars, decorate, isMultiPart); } - - private string Dispatch(object node, ref DynamicSchemaColumn? columnSchema, IDictionary pars = null, bool decorate = true, bool isMultiPart = true) + + private string Dispatch(object node, ref DynamicSchemaColumn? columnSchema, + IDictionary pars = null, bool decorate = true, bool isMultiPart = true) { if (node != null) { if (node is DynamicQueryBuilder) return ParseCommand((DynamicQueryBuilder)node, pars); - else if (node is DynamicParser.Node.Argument) return ParseArgument((DynamicParser.Node.Argument)node, isMultiPart); - else if (node is DynamicParser.Node.GetMember) return ParseGetMember((DynamicParser.Node.GetMember)node, ref columnSchema, pars, decorate, isMultiPart); - else if (node is DynamicParser.Node.SetMember) return ParseSetMember((DynamicParser.Node.SetMember)node, ref columnSchema, pars, decorate, isMultiPart); - else if (node is DynamicParser.Node.Unary) return ParseUnary((DynamicParser.Node.Unary)node, pars); - else if (node is DynamicParser.Node.Binary) return ParseBinary((DynamicParser.Node.Binary)node, pars); - else if (node is DynamicParser.Node.Method) return ParseMethod((DynamicParser.Node.Method)node, ref columnSchema, pars); - else if (node is DynamicParser.Node.Invoke) return ParseInvoke((DynamicParser.Node.Invoke)node, ref columnSchema, pars); - else if (node is DynamicParser.Node.Convert) return ParseConvert((DynamicParser.Node.Convert)node, pars); + else if (node is DynamicParser.Node.Argument) + return ParseArgument((DynamicParser.Node.Argument)node, isMultiPart); + else if (node is DynamicParser.Node.GetMember) + return ParseGetMember((DynamicParser.Node.GetMember)node, ref columnSchema, pars, decorate, + isMultiPart); + else if (node is DynamicParser.Node.SetMember) + return ParseSetMember((DynamicParser.Node.SetMember)node, ref columnSchema, pars, decorate, + isMultiPart); + else if (node is DynamicParser.Node.Unary) + return ParseUnary((DynamicParser.Node.Unary)node, pars); + else if (node is DynamicParser.Node.Binary) + return ParseBinary((DynamicParser.Node.Binary)node, pars); + else if (node is DynamicParser.Node.Method) + return ParseMethod((DynamicParser.Node.Method)node, ref columnSchema, pars); + else if (node is DynamicParser.Node.Invoke) + return ParseInvoke((DynamicParser.Node.Invoke)node, ref columnSchema, pars); + else if (node is DynamicParser.Node.Convert) + return ParseConvert((DynamicParser.Node.Convert)node, pars); } - + // All other cases are considered constant parameters... return ParseConstant(node, pars, columnSchema); } - - internal virtual string ParseCommand(DynamicQueryBuilder node, IDictionary pars = null) + + internal virtual string ParseCommand(DynamicQueryBuilder node, + IDictionary pars = null) { // Getting the command's text... string str = node.CommandText(); // Avoiding spurious "OUTPUT XXX" statements - + // If there are parameters to transform, but cannot store them, it is an error if (node.Parameters.Count != 0 && pars == null) return string.Format("({0})", str); - + // TODO: Make special condiion ////throw new InvalidOperationException(string.Format("The parameters in this command '{0}' cannot be added to a null collection.", node.Parameters)); - + // Copy parameters to new comand foreach (KeyValuePair parameter in node.Parameters) pars.Add(parameter.Key, parameter.Value); - + return string.Format("({0})", str); } - - protected virtual string ParseArgument(DynamicParser.Node.Argument node, bool isMultiPart = true, bool isOwner = false) + + protected virtual string ParseArgument(DynamicParser.Node.Argument node, bool isMultiPart = true, + bool isOwner = false) { if (!string.IsNullOrEmpty(node.Name) && (isOwner || (isMultiPart && IsTableAlias(node.Name)))) return node.Name; - + return null; } - - protected virtual string ParseGetMember(DynamicParser.Node.GetMember node, ref DynamicSchemaColumn? columnSchema, IDictionary pars = null, bool decorate = true, bool isMultiPart = true) + + protected virtual string ParseGetMember(DynamicParser.Node.GetMember node, + ref DynamicSchemaColumn? columnSchema, IDictionary pars = null, + bool decorate = true, bool isMultiPart = true) { if (node.Host is DynamicParser.Node.Argument && IsTableAlias(node.Name)) { decorate = false; isMultiPart = false; } - + // This hack allows to use argument as alias, but when it is not nesesary use other column. // Let say we hace a table Users with alias usr, and we join to table with alias ua which also has a column Users // This allow use of usr => usr.ua.Users to result in ua."Users" instead of "Users" or usr."ua"."Users", se tests for examples. @@ -8989,78 +9350,86 @@ namespace DynamORM { if (isMultiPart && node.Host is DynamicParser.Node.GetMember && IsTable(node.Host.Name, null)) { - if (node.Host.Host != null && node.Host.Host is DynamicParser.Node.GetMember && IsTable(node.Host.Name, node.Host.Host.Name)) - parent = string.Format("{0}.{1}", Parse(node.Host.Host, pars, isMultiPart: false), Parse(node.Host, pars, isMultiPart: false)); + if (node.Host.Host != null && node.Host.Host is DynamicParser.Node.GetMember && + IsTable(node.Host.Name, node.Host.Host.Name)) + parent = string.Format("{0}.{1}", Parse(node.Host.Host, pars, isMultiPart: false), + Parse(node.Host, pars, isMultiPart: false)); else parent = Parse(node.Host, pars, isMultiPart: false); } else if (isMultiPart) parent = Parse(node.Host, pars, isMultiPart: isMultiPart); } - + ////string parent = node.Host == null || !isMultiPart ? null : Parse(node.Host, pars, isMultiPart: !IsTable(node.Name, node.Host.Name)); - string name = parent == null ? - decorate ? Database.DecorateName(node.Name) : node.Name : - string.Format("{0}.{1}", parent, decorate ? Database.DecorateName(node.Name) : node.Name); - + string name = parent == null + ? decorate ? Database.DecorateName(node.Name) : node.Name + : string.Format("{0}.{1}", parent, decorate ? Database.DecorateName(node.Name) : node.Name); + columnSchema = GetColumnFromSchema(name); - + return name; } - - protected virtual string ParseSetMember(DynamicParser.Node.SetMember node, ref DynamicSchemaColumn? columnSchema, IDictionary pars = null, bool decorate = true, bool isMultiPart = true) + + protected virtual string ParseSetMember(DynamicParser.Node.SetMember node, + ref DynamicSchemaColumn? columnSchema, IDictionary pars = null, + bool decorate = true, bool isMultiPart = true) { if (node.Host is DynamicParser.Node.Argument && IsTableAlias(node.Name)) { decorate = false; isMultiPart = false; } - + string parent = null; if (node.Host != null) { if (isMultiPart && node.Host is DynamicParser.Node.GetMember && IsTable(node.Host.Name, null)) { - if (node.Host.Host != null && node.Host.Host is DynamicParser.Node.GetMember && IsTable(node.Name, node.Host.Name)) - parent = string.Format("{0}.{1}", Parse(node.Host.Host, pars, isMultiPart: false), Parse(node.Host, pars, isMultiPart: false)); + if (node.Host.Host != null && node.Host.Host is DynamicParser.Node.GetMember && + IsTable(node.Name, node.Host.Name)) + parent = string.Format("{0}.{1}", Parse(node.Host.Host, pars, isMultiPart: false), + Parse(node.Host, pars, isMultiPart: false)); else parent = Parse(node.Host, pars, isMultiPart: false); } else if (isMultiPart) parent = Parse(node.Host, pars, isMultiPart: isMultiPart); } - + ////string parent = node.Host == null || !isMultiPart ? null : Parse(node.Host, pars, isMultiPart: !IsTable(node.Name, node.Host.Name)); - string name = parent == null ? - decorate ? Database.DecorateName(node.Name) : node.Name : - string.Format("{0}.{1}", parent, decorate ? Database.DecorateName(node.Name) : node.Name); - + string name = parent == null + ? decorate ? Database.DecorateName(node.Name) : node.Name + : string.Format("{0}.{1}", parent, decorate ? Database.DecorateName(node.Name) : node.Name); + columnSchema = GetColumnFromSchema(name); - + string value = Parse(node.Value, ref columnSchema, pars, nulls: true); return string.Format("{0} = ({1})", name, value); } - - protected virtual string ParseUnary(DynamicParser.Node.Unary node, IDictionary pars = null) + + protected virtual string ParseUnary(DynamicParser.Node.Unary node, + IDictionary pars = null) { switch (node.Operation) { // Artifacts from the DynamicParser class that are not usefull here... case ExpressionType.IsFalse: case ExpressionType.IsTrue: return Parse(node.Target, pars); - + // Unary supported operations... case ExpressionType.Not: return string.Format("(NOT {0})", Parse(node.Target, pars)); case ExpressionType.Negate: return string.Format("!({0})", Parse(node.Target, pars)); } - + throw new ArgumentException("Not supported unary operation: " + node); } - - protected virtual string ParseBinary(DynamicParser.Node.Binary node, IDictionary pars = null) + + protected virtual string ParseBinary(DynamicParser.Node.Binary node, + IDictionary pars = null) { string op = string.Empty; - + switch (node.Operation) { // Arithmetic binary operations... @@ -9070,467 +9439,509 @@ namespace DynamORM case ExpressionType.Divide: op = "/"; break; case ExpressionType.Modulo: op = "%"; break; case ExpressionType.Power: op = "^"; break; - + case ExpressionType.And: op = "AND"; break; case ExpressionType.Or: op = "OR"; break; - + // Logical comparisons... case ExpressionType.GreaterThan: op = ">"; break; case ExpressionType.GreaterThanOrEqual: op = ">="; break; case ExpressionType.LessThan: op = "<"; break; case ExpressionType.LessThanOrEqual: op = "<="; break; - + // Comparisons against 'NULL' require the 'IS' or 'IS NOT' operator instead the numeric ones... case ExpressionType.Equal: op = node.Right == null && !VirtualMode ? "IS" : "="; break; case ExpressionType.NotEqual: op = node.Right == null && !VirtualMode ? "IS NOT" : "<>"; break; - + default: throw new ArgumentException("Not supported operator: '" + node.Operation); } - + DynamicSchemaColumn? columnSchema = null; - string left = Parse(node.Left, ref columnSchema, pars); // Not nulls: left is assumed to be an object + string left = Parse(node.Left, ref columnSchema, + pars); // Not nulls: left is assumed to be an object string right = Parse(node.Right, ref columnSchema, pars, nulls: true); return string.Format("({0} {1} {2})", left, op, right); } - - protected virtual string ParseMethod(DynamicParser.Node.Method node, ref DynamicSchemaColumn? columnSchema, IDictionary pars = null) + + protected virtual string ParseMethod(DynamicParser.Node.Method node, + ref DynamicSchemaColumn? columnSchema, IDictionary pars = null) { string method = node.Name.ToUpper(); string parent = node.Host == null ? null : Parse(node.Host, ref columnSchema, pars: pars); string item = null; - + // Root-level methods... if (node.Host == null) { switch (method) { case "NOT": - if (node.Arguments == null || node.Arguments.Length != 1) throw new ArgumentNullException("NOT method expects one argument: " + node.Arguments.Sketch()); + if (node.Arguments == null || node.Arguments.Length != 1) + throw new ArgumentNullException("NOT method expects one argument: " + + node.Arguments.Sketch()); item = Parse(node.Arguments[0], ref columnSchema, pars: pars); return string.Format("(NOT {0})", item); } } - + // Column-level methods... if (node.Host != null) { switch (method) { case "BETWEEN": + { + if (node.Arguments == null || node.Arguments.Length == 0) + throw new ArgumentException("BETWEEN method expects at least one argument: " + + node.Arguments.Sketch()); + + if (node.Arguments.Length > 2) + throw new ArgumentException("BETWEEN method expects at most two arguments: " + + node.Arguments.Sketch()); + + object[] arguments = node.Arguments; + + if (arguments.Length == 1 && + (arguments[0] is IEnumerable || arguments[0] is Array) && + !(arguments[0] is byte[])) { - if (node.Arguments == null || node.Arguments.Length == 0) - throw new ArgumentException("BETWEEN method expects at least one argument: " + node.Arguments.Sketch()); - - if (node.Arguments.Length > 2) - throw new ArgumentException("BETWEEN method expects at most two arguments: " + node.Arguments.Sketch()); - - object[] arguments = node.Arguments; - - if (arguments.Length == 1 && (arguments[0] is IEnumerable || arguments[0] is Array) && !(arguments[0] is byte[])) - { - IEnumerable vals = arguments[0] as IEnumerable; - - if (vals == null && arguments[0] is Array) - vals = ((Array)arguments[0]).Cast() as IEnumerable; - - if (vals != null) - arguments = vals.ToArray(); - else - throw new ArgumentException("BETWEEN method expects single argument to be enumerable of exactly two elements: " + node.Arguments.Sketch()); - } - - return string.Format("{0} BETWEEN {1} AND {2}", parent, Parse(arguments[0], ref columnSchema, pars: pars), Parse(arguments[1], ref columnSchema, pars: pars)); + IEnumerable vals = arguments[0] as IEnumerable; + + if (vals == null && arguments[0] is Array) + vals = ((Array)arguments[0]).Cast() as IEnumerable; + + if (vals != null) + arguments = vals.ToArray(); + else + throw new ArgumentException( + "BETWEEN method expects single argument to be enumerable of exactly two elements: " + + node.Arguments.Sketch()); } - + + return string.Format("{0} BETWEEN {1} AND {2}", parent, + Parse(arguments[0], ref columnSchema, pars: pars), + Parse(arguments[1], ref columnSchema, pars: pars)); + } + case "IN": + { + if (node.Arguments == null || node.Arguments.Length == 0) + throw new ArgumentException("IN method expects at least one argument: " + + node.Arguments.Sketch()); + + bool firstParam = true; + StringBuilder sbin = new StringBuilder(); + foreach (object arg in node.Arguments) { - if (node.Arguments == null || node.Arguments.Length == 0) - throw new ArgumentException("IN method expects at least one argument: " + node.Arguments.Sketch()); - - bool firstParam = true; - StringBuilder sbin = new StringBuilder(); - foreach (object arg in node.Arguments) + if (!firstParam) + sbin.Append(", "); + + if ((arg is IEnumerable || arg is Array) && !(arg is byte[])) { - if (!firstParam) - sbin.Append(", "); - - if ((arg is IEnumerable || arg is Array) && !(arg is byte[])) - { - IEnumerable vals = arg as IEnumerable; - - if (vals == null && arg is Array) - vals = ((Array)arg).Cast() as IEnumerable; - - if (vals != null) - foreach (object val in vals) - { - if (!firstParam) - sbin.Append(", "); - else - firstParam = false; - - sbin.Append(Parse(val, ref columnSchema, pars: pars)); - } - else - sbin.Append(Parse(arg, ref columnSchema, pars: pars)); - } + IEnumerable vals = arg as IEnumerable; + + if (vals == null && arg is Array) + vals = ((Array)arg).Cast() as IEnumerable; + + if (vals != null) + foreach (object val in vals) + { + if (!firstParam) + sbin.Append(", "); + else + firstParam = false; + + sbin.Append(Parse(val, ref columnSchema, pars: pars)); + } else sbin.Append(Parse(arg, ref columnSchema, pars: pars)); - - firstParam = false; } - - return string.Format("{0} IN({1})", parent, sbin.ToString()); + else + sbin.Append(Parse(arg, ref columnSchema, pars: pars)); + + firstParam = false; } - + + return string.Format("{0} IN({1})", parent, sbin.ToString()); + } + case "NOTIN": + { + if (node.Arguments == null || node.Arguments.Length == 0) + throw new ArgumentException("IN method expects at least one argument: " + + node.Arguments.Sketch()); + + bool firstParam = true; + StringBuilder sbin = new StringBuilder(); + foreach (object arg in node.Arguments) { - if (node.Arguments == null || node.Arguments.Length == 0) - throw new ArgumentException("IN method expects at least one argument: " + node.Arguments.Sketch()); - - bool firstParam = true; - StringBuilder sbin = new StringBuilder(); - foreach (object arg in node.Arguments) + if (!firstParam) + sbin.Append(", "); + + if ((arg is IEnumerable || arg is Array) && !(arg is byte[])) { - if (!firstParam) - sbin.Append(", "); - - if ((arg is IEnumerable || arg is Array) && !(arg is byte[])) - { - IEnumerable vals = arg as IEnumerable; - - if (vals == null && arg is Array) - vals = ((Array)arg).Cast() as IEnumerable; - - if (vals != null) - foreach (object val in vals) - { - if (!firstParam) - sbin.Append(", "); - else - firstParam = false; - - sbin.Append(Parse(val, ref columnSchema, pars: pars)); - } - else - sbin.Append(Parse(arg, ref columnSchema, pars: pars)); - } + IEnumerable vals = arg as IEnumerable; + + if (vals == null && arg is Array) + vals = ((Array)arg).Cast() as IEnumerable; + + if (vals != null) + foreach (object val in vals) + { + if (!firstParam) + sbin.Append(", "); + else + firstParam = false; + + sbin.Append(Parse(val, ref columnSchema, pars: pars)); + } else sbin.Append(Parse(arg, ref columnSchema, pars: pars)); - - firstParam = false; } - - return string.Format("{0} NOT IN({1})", parent, sbin.ToString()); + else + sbin.Append(Parse(arg, ref columnSchema, pars: pars)); + + firstParam = false; } - + + return string.Format("{0} NOT IN({1})", parent, sbin.ToString()); + } + case "LIKE": if (node.Arguments == null || node.Arguments.Length != 1) - throw new ArgumentException("LIKE method expects one argument: " + node.Arguments.Sketch()); - - return string.Format("{0} LIKE {1}", parent, Parse(node.Arguments[0], ref columnSchema, pars: pars)); - + throw new ArgumentException("LIKE method expects one argument: " + + node.Arguments.Sketch()); + + return string.Format("{0} LIKE {1}", parent, + Parse(node.Arguments[0], ref columnSchema, pars: pars)); + case "NOTLIKE": if (node.Arguments == null || node.Arguments.Length != 1) - throw new ArgumentException("NOT LIKE method expects one argument: " + node.Arguments.Sketch()); - - return string.Format("{0} NOT LIKE {1}", parent, Parse(node.Arguments[0], ref columnSchema, pars: pars)); - + throw new ArgumentException("NOT LIKE method expects one argument: " + + node.Arguments.Sketch()); + + return string.Format("{0} NOT LIKE {1}", parent, + Parse(node.Arguments[0], ref columnSchema, pars: pars)); + case "AS": if (node.Arguments == null || node.Arguments.Length != 1) - throw new ArgumentException("AS method expects one argument: " + node.Arguments.Sketch()); - - item = Parse(node.Arguments[0], pars: null, rawstr: true, isMultiPart: false); // pars=null to avoid to parameterize aliases + throw new ArgumentException("AS method expects one argument: " + + node.Arguments.Sketch()); + + item = Parse(node.Arguments[0], pars: null, rawstr: true, + isMultiPart: false); // pars=null to avoid to parameterize aliases item = item.Validated("Alias"); // Intercepting null and empty aliases return string.Format("{0} AS {1}", parent, item); - + case "NOLOCK": if (!SupportNoLock) return parent; - + if (node.Arguments != null && node.Arguments.Length > 1) throw new ArgumentException("NOLOCK method expects no arguments."); - + return string.Format("{0} {1}", parent, "WITH(NOLOCK)"); - + case "COUNT": if (node.Arguments != null && node.Arguments.Length > 1) - throw new ArgumentException("COUNT method expects one or none argument: " + node.Arguments.Sketch()); - + throw new ArgumentException("COUNT method expects one or none argument: " + + node.Arguments.Sketch()); + if (node.Arguments == null || node.Arguments.Length == 0) return "COUNT(*)"; - - return string.Format("COUNT({0})", Parse(node.Arguments[0], ref columnSchema, pars: Parameters, nulls: true)); - + + return string.Format("COUNT({0})", + Parse(node.Arguments[0], ref columnSchema, pars: Parameters, nulls: true)); + case "COUNT0": if (node.Arguments != null && node.Arguments.Length > 0) throw new ArgumentException("COUNT0 method doesn't expect arguments"); - + return "COUNT(0)"; } } - + // Default case: parsing the method's name along with its arguments... method = parent == null ? node.Name : string.Format("{0}.{1}", parent, node.Name); StringBuilder sb = new StringBuilder(); sb.AppendFormat("{0}(", method); - + if (node.Arguments != null && node.Arguments.Length != 0) { bool first = true; - + foreach (object argument in node.Arguments) { if (!first) sb.Append(", "); else first = false; - - sb.Append(Parse(argument, ref columnSchema, pars, nulls: true)); // We don't accept raw strings here!!! + + sb.Append(Parse(argument, ref columnSchema, pars, + nulls: true)); // We don't accept raw strings here!!! } } - + sb.Append(")"); return sb.ToString(); } - - protected virtual string ParseInvoke(DynamicParser.Node.Invoke node, ref DynamicSchemaColumn? columnSchema, IDictionary pars = null) + + protected virtual string ParseInvoke(DynamicParser.Node.Invoke node, + ref DynamicSchemaColumn? columnSchema, IDictionary pars = null) { // This is used as an especial syntax to merely concatenate its arguments. It is used as a way to extend the supported syntax without the need of treating all the possible cases... if (node.Arguments == null || node.Arguments.Length == 0) return string.Empty; - + StringBuilder sb = new StringBuilder(); foreach (object arg in node.Arguments) { if (arg is string) { sb.Append((string)arg); - + if (node.Arguments.Length == 1 && !columnSchema.HasValue) columnSchema = GetColumnFromSchema((string)arg); } else sb.Append(Parse(arg, ref columnSchema, pars, rawstr: true, nulls: true)); } - + return sb.ToString(); } - - protected virtual string ParseConvert(DynamicParser.Node.Convert node, IDictionary pars = null) + + protected virtual string ParseConvert(DynamicParser.Node.Convert node, + IDictionary pars = null) { // The cast mechanism is left for the specific database implementation, that should override this method // as needed... string r = Parse(node.Target, pars); return r; } - - protected virtual string ParseConstant(object node, IDictionary pars = null, DynamicSchemaColumn? columnSchema = null) + + protected virtual string ParseConstant(object node, IDictionary pars = null, + DynamicSchemaColumn? columnSchema = null) { if (node == null && !VirtualMode) return ParseNull(); - + if (pars != null) { - bool wellKnownName = VirtualMode && node is String && ((String)node).StartsWith("[$") && ((String)node).EndsWith("]") && ((String)node).Length > 4; - + bool wellKnownName = VirtualMode && node is String && ((String)node).StartsWith("[$") && + ((String)node).EndsWith("]") && ((String)node).Length > 4; + // If we have a list of parameters to store it, let's parametrize it Parameter par = new Parameter() { - Name = wellKnownName ? ((String)node).Substring(2, ((String)node).Length - 3) : Guid.NewGuid().ToString(), + Name = wellKnownName + ? ((String)node).Substring(2, ((String)node).Length - 3) + : Guid.NewGuid().ToString(), Value = wellKnownName ? null : node, WellKnown = wellKnownName, Virtual = VirtualMode, Schema = columnSchema, }; - + // If we are adding parameter we inform external sources about this. if (OnCreateTemporaryParameter != null) OnCreateTemporaryParameter.ForEach(x => x(par)); - + pars.Add(par.Name, par); - + return string.Format("[${0}]", par.Name); } - + return node.ToString(); // Last resort case } - + protected virtual string ParseNull() { return "NULL"; // Override if needed } - + #endregion Parser - + #region Helpers - + internal bool IsTableAlias(string name) { DynamicQueryBuilder builder = this; - + while (builder != null) { if (builder.Tables.Any(t => t.Alias == name)) return true; - + builder = builder._parent; } - + return false; } - + internal bool IsTable(string name, string owner) { DynamicQueryBuilder builder = this; - + while (builder != null) { - if ((string.IsNullOrEmpty(owner) && builder.Tables.Any(t => t.Name.ToLower() == name.ToLower())) || - (!string.IsNullOrEmpty(owner) && builder.Tables.Any(t => t.Name.ToLower() == name.ToLower() && + if ((string.IsNullOrEmpty(owner) && + builder.Tables.Any(t => t.Name.ToLower() == name.ToLower())) || + (!string.IsNullOrEmpty(owner) && builder.Tables.Any(t => + t.Name.ToLower() == name.ToLower() && !string.IsNullOrEmpty(t.Owner) && t.Owner.ToLower() == owner.ToLower()))) return true; - + builder = builder._parent; } - + return false; } - + internal string FixObjectName(string main, bool onlyColumn = false) { if (main.IndexOf("(") > 0 && main.IndexOf(")") > 0) - return main.FillStringWithVariables(f => string.Format("({0})", FixObjectNamePrivate(f, onlyColumn)), "(", ")"); + return main.FillStringWithVariables( + f => string.Format("({0})", FixObjectNamePrivate(f, onlyColumn)), "(", ")"); else return FixObjectNamePrivate(main, onlyColumn); } - + private string FixObjectNamePrivate(string f, bool onlyColumn = false) { IEnumerable objects = f.Split('.') .Select(x => Database.StripName(x)); - + if (onlyColumn || objects.Count() == 1) f = Database.DecorateName(objects.Last()); else if (!IsTableAlias(objects.First())) f = string.Join(".", objects.Select(o => Database.DecorateName(o))); else - f = string.Format("{0}.{1}", objects.First(), string.Join(".", objects.Skip(1).Select(o => Database.DecorateName(o)))); - + f = string.Format("{0}.{1}", objects.First(), + string.Join(".", objects.Skip(1).Select(o => Database.DecorateName(o)))); + return f; } - - internal DynamicSchemaColumn? GetColumnFromSchema(string colName, DynamicTypeMap mapper = null, string table = null) + + internal DynamicSchemaColumn? GetColumnFromSchema(string colName, DynamicTypeMap mapper = null, + string table = null) { // This is tricky and will not always work unfortunetly. ////if (colName.ContainsAny(StringExtensions.InvalidMultipartMemberChars)) //// return null; - + // First we need to get real column name and it's owner if exist. string[] parts = colName.Split('.'); for (int i = 0; i < parts.Length; i++) parts[i] = Database.StripName(parts[i]); - + string columnName = parts.Last(); - + // Get table name from mapper string tableName = table; - + if (string.IsNullOrEmpty(tableName)) { tableName = (mapper != null && mapper.Table != null) ? mapper.Table.Name : string.Empty; - + if (parts.Length > 1 && string.IsNullOrEmpty(tableName)) { // OK, we have a multi part identifier, that's good, we can get table name tableName = string.Join(".", parts.Take(parts.Length - 1)); } } - + // Try to get table info from cache - ITableInfo tableInfo = !string.IsNullOrEmpty(tableName) ? + ITableInfo tableInfo = !string.IsNullOrEmpty(tableName) + ? Tables.FirstOrDefault(x => !string.IsNullOrEmpty(x.Alias) && x.Alias.ToLower() == tableName) ?? - Tables.FirstOrDefault(x => x.Name.ToLower() == tableName.ToLower()) ?? Tables.FirstOrDefault() : - this is DynamicModifyBuilder || Tables.Count == 1 ? Tables.FirstOrDefault() : null; - + Tables.FirstOrDefault(x => x.Name.ToLower() == tableName.ToLower()) ?? Tables.FirstOrDefault() + : + this is DynamicModifyBuilder || Tables.Count == 1 + ? Tables.FirstOrDefault() + : null; + // Try to get column from schema if (tableInfo != null && tableInfo.Schema != null) return tableInfo.Schema.TryGetNullable(columnName.ToLower()); - + // Well, we failed to find a column return null; } - + #endregion Helpers - + #region IExtendedDisposable - + /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public virtual void Dispose() { IsDisposed = true; - + if (Database != null) Database.RemoveFromCache(this); - + if (Parameters != null) { foreach (KeyValuePair p in Parameters) p.Value.Dispose(); - + Parameters.Clear(); Parameters = null; } - + if (Tables != null) { foreach (ITableInfo t in Tables) if (t != null) t.Dispose(); - + Tables.Clear(); Tables = null; } - + WhereCondition = null; Database = null; } - + #endregion IExtendedDisposable } - + /// Implementation of dynamic select query builder. - internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, DynamicQueryBuilder.IQueryWithWhere, DynamicQueryBuilder.IQueryWithHaving + internal class DynamicSelectQueryBuilder : DynamicQueryBuilder, IDynamicSelectQueryBuilder, + DynamicQueryBuilder.IQueryWithWhere, DynamicQueryBuilder.IQueryWithHaving { private int? _limit = null; private int? _offset = null; private bool _distinct = false; - + private string _select; private string _from; private string _join; private string _groupby; private string _orderby; - + #region IQueryWithHaving - + /// Gets or sets the having condition. public string HavingCondition { get; set; } - + /// Gets or sets the amount of not closed brackets in having statement. public int HavingOpenBracketsCount { get; set; } - + #endregion IQueryWithHaving - + /// /// Gets a value indicating whether this instance has select columns. /// - public bool HasSelectColumns { get { return !string.IsNullOrEmpty(_select); } } - + public bool HasSelectColumns + { + get { return !string.IsNullOrEmpty(_select); } + } + /// /// Initializes a new instance of the class. /// @@ -9539,7 +9950,7 @@ namespace DynamORM : base(db) { } - + /// /// Initializes a new instance of the class. /// @@ -9549,17 +9960,17 @@ namespace DynamORM : base(db, parent) { } - + /// Generates the text this command will execute against the underlying database. /// The text to execute against the underlying database. public override string CommandText() { bool lused = false; bool oused = false; - + StringBuilder sb = new StringBuilder("SELECT"); if (_distinct) sb.AppendFormat(" DISTINCT"); - + if (_limit.HasValue) { if ((Database.Options & DynamicDatabaseOptions.SupportTop) == DynamicDatabaseOptions.SupportTop) @@ -9567,116 +9978,119 @@ namespace DynamORM sb.AppendFormat(" TOP {0}", _limit); lused = true; } - else if ((Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == DynamicDatabaseOptions.SupportFirstSkip) + else if ((Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == + DynamicDatabaseOptions.SupportFirstSkip) { sb.AppendFormat(" FIRST {0}", _limit); lused = true; } } - - if (_offset.HasValue && (Database.Options & DynamicDatabaseOptions.SupportFirstSkip) == DynamicDatabaseOptions.SupportFirstSkip) + + 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 (_join != null) sb.AppendFormat(" {0}", _join); if (WhereCondition != null) sb.AppendFormat(" WHERE {0}", WhereCondition); if (_groupby != null) sb.AppendFormat(" GROUP BY {0}", _groupby); if (HavingCondition != null) sb.AppendFormat(" HAVING {0}", HavingCondition); if (_orderby != null) sb.AppendFormat(" ORDER BY {0}", _orderby); - if (_limit.HasValue && !lused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == DynamicDatabaseOptions.SupportLimitOffset) + 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) + if (_offset.HasValue && !oused && (Database.Options & DynamicDatabaseOptions.SupportLimitOffset) == + DynamicDatabaseOptions.SupportLimitOffset) sb.AppendFormat(" OFFSET {0}", _offset); - + return sb.ToString(); } - + #region Execution - + /// Execute this builder. /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() { - DynamicCachedReader cache = null; using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.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 + .SetCommand(this) + .ExecuteReader()) + using (IDataReader cache = new DynamicCachedReader(rdr)) + while (cache.Read()) { - val = cache.RowToDynamic(); + 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 = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder 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; } - catch (ArgumentException argex) - { - StringBuilder 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; - } } } - + /// Execute this builder and map to given type. /// Type of object to map on. /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() where T : class { - DynamicCachedReader cache = null; DynamicTypeMap mapper = DynamicMapperCache.GetMapper(); - + if (mapper == null) throw new InvalidOperationException("Type can't be mapped for unknown reason."); - + using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.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 + .SetCommand(this) + .ExecuteReader()) + using (IDataReader cache = new DynamicCachedReader(rdr)) + while (cache.Read()) { - val = cache.RowToDynamic(); + 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 = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder 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 mapper.Create(val) as T; } - catch (ArgumentException argex) - { - StringBuilder 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 mapper.Create(val) as T; - } } } - + /// Execute this builder as a data reader. /// Action containing reader. public virtual void ExecuteDataReader(Action reader) @@ -9684,28 +10098,25 @@ namespace DynamORM using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) + .SetCommand(this) + .ExecuteReader()) reader(rdr); } - + /// 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) { - DynamicCachedReader cache = null; - using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - reader(cache); + .SetCommand(this) + .ExecuteReader()) + using (IDataReader cache = new DynamicCachedReader(rdr)) + reader(cache); } - + /// Returns a single result. /// Result of a query. public virtual object Scalar() @@ -9718,9 +10129,9 @@ namespace DynamORM .ExecuteScalar(); } } - - #if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE - + +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + /// Returns a single result. /// Type to parse to. /// Default value. @@ -9735,13 +10146,13 @@ namespace DynamORM .ExecuteScalarAs(defaultValue); } } - - #endif - + +#endif + #endregion Execution - + #region From/Join - + /// /// Adds to the 'From' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -9753,29 +10164,30 @@ namespace DynamORM /// The specification. /// The specification. /// This instance to permit chaining. - public virtual IDynamicSelectQueryBuilder From(Func fn, params Func[] func) + public virtual IDynamicSelectQueryBuilder From(Func fn, + params Func[] func) { if (fn == null) throw new ArgumentNullException("Array of functions cannot be or contain null."); - + int index = FromFunc(-1, fn); foreach (Func f in func) index = FromFunc(index, f); - + return this; } - + private int FromFunc(int index, Func f) { if (f == null) throw new ArgumentNullException("Array of functions cannot be or contain null."); - + index++; ITableInfo tableInfo = null; using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; - + // If the expression result is string. if (result is string) { @@ -9785,95 +10197,105 @@ namespace DynamORM tableInfo = new TableInfo(Database, Database.StripName(parts.Last()).Validated("Table"), tuple.Item2.Validated("Alias", canbeNull: true), - parts.Length == 2 ? Database.StripName(parts.First()).Validated("Owner", canbeNull: true) : null); + parts.Length == 2 + ? Database.StripName(parts.First()).Validated("Owner", canbeNull: true) + : null); } else if (result is Type) { Type type = (Type)result; if (type.IsAnonymous()) - throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); - + throw new InvalidOperationException(string.Format( + "Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); - + if (mapper == null) - throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); - + throw new InvalidOperationException(string.Format( + "Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); + tableInfo = new TableInfo(Database, type); } else if (result is DynamicParser.Node) { // Or if it resolves to a dynamic node DynamicParser.Node node = (DynamicParser.Node)result; - + string owner = null; string main = null; string alias = null; bool nolock = false; Type type = null; - + while (true) { // Support for the AS() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") { if (alias != null) - throw new ArgumentException(string.Format("Alias '{0}' is already set when parsing '{1}'.", alias, result)); - + throw new ArgumentException(string.Format( + "Alias '{0}' is already set when parsing '{1}'.", alias, result)); + object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args == null) throw new ArgumentNullException("arg", "AS() is not a parameterless method."); - + if (args.Length != 1) - throw new ArgumentException("AS() requires one and only one parameter: " + args.Sketch()); - + throw new ArgumentException("AS() requires one and only one parameter: " + + args.Sketch()); + alias = Parse(args[0], rawstr: true, decorate: false).Validated("Alias"); - + node = node.Host; continue; } - + // Support for the NoLock() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "NOLOCK") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "NOLOCK") { object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args != null && args.Length > 0) throw new ArgumentNullException("arg", "NoLock() doesn't support arguments."); - + nolock = true; - + node = node.Host; 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).Cast>().ToArray()), Parameters); continue; }*/ - + // Support for table specifications... if (node is DynamicParser.Node.GetMember) { if (owner != null) - throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); - + throw new ArgumentException(string.Format( + "Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); + if (main != null) owner = ((DynamicParser.Node.GetMember)node).Name; else main = ((DynamicParser.Node.GetMember)node).Name; - + node = node.Host; continue; } - + // Support for generic sources... if (node is DynamicParser.Node.Invoke) { if (owner != null) - throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); - + throw new ArgumentException(string.Format( + "Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); + if (main != null) owner = string.Format("{0}", Parse(node, rawstr: true, pars: Parameters)); else @@ -9883,70 +10305,85 @@ namespace DynamORM { type = (Type)invoke.Arguments[0]; if (type.IsAnonymous()) - throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); - + throw new InvalidOperationException( + string.Format( + "Cant assign anonymous type as a table ({0}). Parsing {1}", + type.FullName, result)); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); - + if (mapper == null) - throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); - - main = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - mapper.Type.Name : mapper.Table.Name; - + throw new InvalidOperationException( + string.Format( + "Cant assign unmapable type as a table ({0}). Parsing {1}", + type.FullName, result)); + + main = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) + ? mapper.Type.Name + : mapper.Table.Name; + owner = (mapper.Table != null) ? mapper.Table.Owner : owner; } else main = string.Format("{0}", Parse(node, rawstr: true, pars: Parameters)); } - + node = node.Host; continue; } - + // Just finished the parsing... if (node is DynamicParser.Node.Argument) break; - + // All others are assumed to be part of the main element... if (main != null) main = Parse(node, pars: Parameters); else main = Parse(node, pars: Parameters); - + break; } - + if (!string.IsNullOrEmpty(main)) - tableInfo = type == null ? new TableInfo(Database, main, alias, owner, nolock) : new TableInfo(Database, type, alias, owner, nolock); + tableInfo = type == null + ? new TableInfo(Database, main, alias, owner, nolock) + : new TableInfo(Database, type, alias, owner, nolock); else - throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, result)); + throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, + result)); } - + // Or it is a not supported expression... if (tableInfo == null) - throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, result)); - + throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, + result)); + Tables.Add(tableInfo); - + // We finally add the contents... StringBuilder sb = new StringBuilder(); - + if (!string.IsNullOrEmpty(tableInfo.Owner)) sb.AppendFormat("{0}.", Database.DecorateName(tableInfo.Owner)); - - sb.Append(tableInfo.Name.ContainsAny(StringExtensions.InvalidMemberChars) ? tableInfo.Name : Database.DecorateName(tableInfo.Name)); - + + sb.Append(tableInfo.Name.ContainsAny(StringExtensions.InvalidMemberChars) + ? tableInfo.Name + : Database.DecorateName(tableInfo.Name)); + if (!string.IsNullOrEmpty(tableInfo.Alias)) sb.AppendFormat(" AS {0}", tableInfo.Alias); - + if (SupportNoLock && tableInfo.NoLock) sb.AppendFormat(" WITH(NOLOCK)"); - - _from = string.IsNullOrEmpty(_from) ? sb.ToString() : string.Format("{0}, {1}", _from, sb.ToString()); + + _from = string.IsNullOrEmpty(_from) + ? sb.ToString() + : string.Format("{0}, {1}", _from, sb.ToString()); } - + return index; } - + /// /// Adds to the 'Join' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -9968,7 +10405,7 @@ namespace DynamORM // We need to do two passes to add aliases first. return JoinInternal(true, func).JoinInternal(false, func); } - + /// /// Adds to the 'Join' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -9986,25 +10423,28 @@ namespace DynamORM /// If true just pass by to locate tables and aliases, otherwise create rules. /// The specification. /// This instance to permit chaining. - protected virtual DynamicSelectQueryBuilder JoinInternal(bool justAddTables, params Func[] func) + protected virtual DynamicSelectQueryBuilder JoinInternal(bool justAddTables, + params Func[] func) { if (func == null) throw new ArgumentNullException("Array of functions cannot be null."); - + int index = -1; - + foreach (Func f in func) { index++; ITableInfo tableInfo = null; - + if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; - if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - + if (result == null) + throw new ArgumentException( + string.Format("Specification #{0} resolves to null.", index)); + string type = null; string main = null; string owner = null; @@ -10012,14 +10452,14 @@ namespace DynamORM string condition = null; bool nolock = false; Type tableType = null; - + // If the expression resolves to a string... if (result is string) { string node = (string)result; - + int n = node.ToUpper().IndexOf("JOIN "); - + if (n < 0) main = node; else @@ -10028,19 +10468,23 @@ namespace DynamORM type = node.Substring(0, n + 4); main = node.Substring(n + 4); } - + n = main.ToUpper().IndexOf("ON"); - + if (n >= 0) { condition = main.Substring(n + 3); main = main.Substring(0, n).Trim(); } - - Tuple tuple = main.SplitSomethingAndAlias(); // In this case we split on the remaining 'main' + + Tuple + tuple = main + .SplitSomethingAndAlias(); // In this case we split on the remaining 'main' string[] parts = tuple.Item1.Split('.'); main = Database.StripName(parts.Last()).Validated("Table"); - owner = parts.Length == 2 ? Database.StripName(parts.First()).Validated("Owner", canbeNull: true) : null; + owner = parts.Length == 2 + ? Database.StripName(parts.First()).Validated("Owner", canbeNull: true) + : null; alias = tuple.Item2.Validated("Alias", canbeNull: true); } else if (result is DynamicParser.Node) @@ -10050,82 +10494,100 @@ namespace DynamORM while (true) { // Support for the ON() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "ON") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "ON") { if (condition != null) - throw new ArgumentException(string.Format("Condition '{0}' is already set when parsing '{1}'.", alias, result)); - + throw new ArgumentException(string.Format( + "Condition '{0}' is already set when parsing '{1}'.", alias, result)); + object[] args = ((DynamicParser.Node.Method)node).Arguments; if (args == null) - throw new ArgumentNullException("arg", "ON() is not a parameterless method."); - + throw new ArgumentNullException("arg", + "ON() is not a parameterless method."); + if (args.Length != 1) - throw new ArgumentException("ON() requires one and only one parameter: " + args.Sketch()); - - condition = Parse(args[0], rawstr: true, pars: justAddTables ? null : Parameters); - + throw new ArgumentException("ON() requires one and only one parameter: " + + args.Sketch()); + + condition = Parse(args[0], rawstr: true, + pars: justAddTables ? null : Parameters); + node = node.Host; continue; } - + // Support for the AS() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") { if (alias != null) - throw new ArgumentException(string.Format("Alias '{0}' is already set when parsing '{1}'.", alias, result)); - + throw new ArgumentException(string.Format( + "Alias '{0}' is already set when parsing '{1}'.", alias, result)); + object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args == null) - throw new ArgumentNullException("arg", "AS() is not a parameterless method."); - + throw new ArgumentNullException("arg", + "AS() is not a parameterless method."); + if (args.Length != 1) - throw new ArgumentException("AS() requires one and only one parameter: " + args.Sketch()); - - alias = Parse(args[0], rawstr: true, decorate: false, isMultiPart: false).Validated("Alias"); - + throw new ArgumentException("AS() requires one and only one parameter: " + + args.Sketch()); + + alias = Parse(args[0], rawstr: true, decorate: false, isMultiPart: false) + .Validated("Alias"); + node = node.Host; continue; } - + // Support for the NoLock() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "NOLOCK") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "NOLOCK") { object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args != null && args.Length > 0) - throw new ArgumentNullException("arg", "NoLock() doesn't support arguments."); - + throw new ArgumentNullException("arg", + "NoLock() doesn't support arguments."); + nolock = true; - + node = node.Host; continue; } - + // Support for table specifications... if (node is DynamicParser.Node.GetMember) { if (owner != null) - throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); - + throw new ArgumentException(string.Format( + "Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, + result)); + if (main != null) owner = ((DynamicParser.Node.GetMember)node).Name; else main = ((DynamicParser.Node.GetMember)node).Name; - + node = node.Host; continue; } - + // Support for Join Type specifications... - if (node is DynamicParser.Node.Method && (node.Host is DynamicParser.Node.Argument || node.Host is DynamicParser.Node.Invoke)) + 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)); + 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; - + bool avoid = false; object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args != null && args.Length > 0) { avoid = args[0] is bool && !((bool)args[0]); @@ -10133,7 +10595,7 @@ namespace DynamORM if (!string.IsNullOrEmpty(proposedType)) type = proposedType; } - + type = type.ToUpper(); // Normalizing, and stepping out the trivial case... if (type != "JOIN") { @@ -10142,13 +10604,13 @@ namespace DynamORM type = type.Replace("OUTER", " OUTER ") .Replace(" ", " ") .Trim(' '); - + // x => x.Left()... int n = type.IndexOf("JOIN"); - + if (n < 0 && !avoid) type += " JOIN"; - + // x => x.InnerJoin() / x => x.JoinLeft() ... else { @@ -10159,19 +10621,22 @@ namespace DynamORM } } } - + node = node.Host; continue; } - + // Support for generic sources... if (node is DynamicParser.Node.Invoke) { if (owner != null) - throw new ArgumentException(string.Format("Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, result)); - + throw new ArgumentException(string.Format( + "Owner '{0}.{1}' is already set when parsing '{2}'.", owner, main, + result)); + if (main != null) - owner = string.Format("{0}", Parse(node, rawstr: true, pars: justAddTables ? null : Parameters)); + owner = string.Format("{0}", + Parse(node, rawstr: true, pars: justAddTables ? null : Parameters)); else { DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node; @@ -10179,86 +10644,99 @@ namespace DynamORM { tableType = (Type)invoke.Arguments[0]; DynamicTypeMap mapper = DynamicMapperCache.GetMapper(tableType); - + if (mapper == null) - throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", tableType.FullName)); - - main = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - mapper.Type.Name : mapper.Table.Name; - + throw new InvalidOperationException( + string.Format("Cant assign unmapable type as a table ({0}).", + tableType.FullName)); + + main = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) + ? mapper.Type.Name + : mapper.Table.Name; + owner = (mapper.Table != null) ? mapper.Table.Owner : owner; } else - main = string.Format("{0}", Parse(node, rawstr: true, pars: justAddTables ? null : Parameters)); + main = string.Format("{0}", + Parse(node, rawstr: true, pars: justAddTables ? null : Parameters)); } - + node = node.Host; continue; } - + // Just finished the parsing... if (node is DynamicParser.Node.Argument) break; - throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, result)); + throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", + index, result)); } } else { // Or it is a not supported expression... - throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, result)); + throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, + result)); } - + // We annotate the aliases being conservative... main = main.Validated("Main"); - + if (justAddTables) { if (!string.IsNullOrEmpty(main)) - tableInfo = tableType == null ? new TableInfo(Database, main, alias, owner, nolock) : new TableInfo(Database, tableType, alias, owner, nolock); + tableInfo = tableType == null + ? new TableInfo(Database, main, alias, owner, nolock) + : new TableInfo(Database, tableType, alias, owner, nolock); else - throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, result)); - + throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", + index, result)); + Tables.Add(tableInfo); } else { // Get cached table info - tableInfo = string.IsNullOrEmpty(alias) ? - Tables.SingleOrDefault(t => t.Name == main && string.IsNullOrEmpty(t.Alias)) : - Tables.SingleOrDefault(t => t.Alias == alias); - + tableInfo = string.IsNullOrEmpty(alias) + ? Tables.SingleOrDefault(t => t.Name == main && string.IsNullOrEmpty(t.Alias)) + : Tables.SingleOrDefault(t => t.Alias == alias); + // We finally add the contents if we can... StringBuilder sb = new StringBuilder(); if (string.IsNullOrEmpty(type)) type = "JOIN"; - + sb.AppendFormat("{0} ", type); - + if (!string.IsNullOrEmpty(tableInfo.Owner)) sb.AppendFormat("{0}.", Database.DecorateName(tableInfo.Owner)); - - sb.Append(tableInfo.Name.ContainsAny(StringExtensions.InvalidMemberChars) ? tableInfo.Name : Database.DecorateName(tableInfo.Name)); - + + sb.Append(tableInfo.Name.ContainsAny(StringExtensions.InvalidMemberChars) + ? tableInfo.Name + : Database.DecorateName(tableInfo.Name)); + if (!string.IsNullOrEmpty(tableInfo.Alias)) sb.AppendFormat(" AS {0}", tableInfo.Alias); - + if (SupportNoLock && tableInfo.NoLock) sb.AppendFormat(" WITH(NOLOCK)"); - + if (!string.IsNullOrEmpty(condition)) sb.AppendFormat(" ON {0}", condition); - - _join = string.IsNullOrEmpty(_join) ? sb.ToString() : string.Format("{0} {1}", _join, sb.ToString()); // No comma in this case + + _join = string.IsNullOrEmpty(_join) + ? sb.ToString() + : string.Format("{0} {1}", _join, sb.ToString()); // No comma in this case } } } - + return this; } - + #endregion From/Join - + #region Where - + /// /// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used @@ -10273,7 +10751,7 @@ namespace DynamORM { return this.InternalWhere(func); } - + /// Add where condition. /// Condition column with operator and value. /// Builder instance. @@ -10281,17 +10759,18 @@ namespace DynamORM { return this.InternalWhere(column); } - + /// Add where condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. - public virtual IDynamicSelectQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value) + public virtual IDynamicSelectQueryBuilder Where(string column, DynamicColumn.CompareOperator op, + object value) { return this.InternalWhere(column, op, value); } - + /// Add where condition. /// Condition column. /// Condition value. @@ -10300,7 +10779,7 @@ namespace DynamORM { return this.InternalWhere(column, value); } - + /// Add where condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which @@ -10310,11 +10789,11 @@ namespace DynamORM { return this.InternalWhere(conditions, schema); } - + #endregion Where - + #region Select - + /// /// Adds to the 'Select' clause the contents obtained by parsing the dynamic lambda expressions given. The supported /// formats are: @@ -10327,45 +10806,46 @@ namespace DynamORM /// The specification. /// The specification. /// This instance to permit chaining. - public virtual IDynamicSelectQueryBuilder Select(Func fn, params Func[] func) + public virtual IDynamicSelectQueryBuilder Select(Func fn, + params Func[] func) { if (fn == null) throw new ArgumentNullException("Array of specifications cannot be null."); - + int index = SelectFunc(-1, fn); if (func != null) foreach (Func f in func) index = SelectFunc(index, f); - + return this; } - + private int SelectFunc(int index, Func f) { index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - + string main = null; string alias = null; bool all = false; bool anon = false; - + // If the expression resolves to a string... if (result is string) { string node = (string)result; Tuple tuple = node.SplitSomethingAndAlias(); main = tuple.Item1.Validated("Table and/or Column"); - + main = FixObjectName(main); - + alias = tuple.Item2.Validated("Alias", canbeNull: true); } else if (result is DynamicParser.Node) @@ -10376,7 +10856,7 @@ namespace DynamORM else if (result.GetType().IsAnonymous()) { anon = true; - + foreach (KeyValuePair prop in result.ToDictionary()) { if (prop.Value is string) @@ -10384,7 +10864,7 @@ namespace DynamORM string node = (string)prop.Value; Tuple tuple = node.SplitSomethingAndAlias(); main = FixObjectName(tuple.Item1.Validated("Table and/or Column")); - + ////alias = tuple.Item2.Validated("Alias", canbeNull: true); } else if (prop.Value is DynamicParser.Node) @@ -10395,9 +10875,10 @@ namespace DynamORM else { // Or it is a not supported expression... - throw new ArgumentException(string.Format("Specification #{0} in anonymous type is invalid: {1}", index, prop.Value)); + throw new ArgumentException(string.Format( + "Specification #{0} in anonymous type is invalid: {1}", index, prop.Value)); } - + alias = Database.DecorateName(prop.Key); ParseSelectAddColumn(main, alias, all); } @@ -10405,16 +10886,17 @@ namespace DynamORM else { // Or it is a not supported expression... - throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, result)); + throw new ArgumentException(string.Format("Specification #{0} is invalid: {1}", index, + result)); } - + if (!anon) ParseSelectAddColumn(main, alias, all); } - + return index; } - + /// Add select columns. /// Columns to add to object. /// Builder instance. @@ -10422,10 +10904,10 @@ namespace DynamORM { foreach (DynamicColumn col in columns) Select(x => col.ToSQLSelectColumn(Database)); - + return this; } - + /// Add select columns. /// Columns to add to object. /// Column format consist of Column Name, Alias and @@ -10436,66 +10918,67 @@ namespace DynamORM DynamicColumn[] cols = new DynamicColumn[columns.Length]; for (int i = 0; i < columns.Length; i++) cols[i] = DynamicColumn.ParseSelectColumn(columns[i]); - + return SelectColumn(cols); } - + #endregion Select - + #region GroupBy - + /// /// Adds to the 'Group By' clause the contents obtained from from parsing the dynamic lambda expression given. /// /// The specification. /// The specification. /// This instance to permit chaining. - public virtual IDynamicSelectQueryBuilder GroupBy(Func fn, params Func[] func) + public virtual IDynamicSelectQueryBuilder GroupBy(Func fn, + params Func[] func) { if (fn == null) throw new ArgumentNullException("Array of specifications cannot be null."); - + int index = GroupByFunc(-1, fn); - + if (func != null) for (int i = 0; i < func.Length; i++) { Func f = func[i]; index = GroupByFunc(index, f); } - + return this; } - + private int GroupByFunc(int index, Func f) { index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - + string main = null; - + if (result is string) main = FixObjectName(result as string); else main = Parse(result, pars: Parameters); - + main = main.Validated("Group By"); if (_groupby == null) _groupby = main; else _groupby = string.Format("{0}, {1}", _groupby, main); } - + return index; } - + /// Add select columns. /// Columns to group by. /// Builder instance. @@ -10506,10 +10989,10 @@ namespace DynamORM DynamicColumn col = columns[i]; GroupBy(x => col.ToSQLGroupByColumn(Database)); } - + return this; } - + /// Add select columns. /// Columns to group by. /// Column format consist of Column Name and @@ -10519,11 +11002,11 @@ namespace DynamORM { return GroupByColumn(columns.Select(c => DynamicColumn.ParseSelectColumn(c)).ToArray()); } - + #endregion GroupBy - + #region Having - + /// /// Adds to the 'Having' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, Having the specific customs virtual methods supported by the parser are used @@ -10538,7 +11021,7 @@ namespace DynamORM { return this.InternalHaving(func); } - + /// Add Having condition. /// Condition column with operator and value. /// Builder instance. @@ -10546,17 +11029,18 @@ namespace DynamORM { return this.InternalHaving(column); } - + /// Add Having condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. - public virtual IDynamicSelectQueryBuilder Having(string column, DynamicColumn.CompareOperator op, object value) + public virtual IDynamicSelectQueryBuilder Having(string column, DynamicColumn.CompareOperator op, + object value) { return this.InternalHaving(column, op, value); } - + /// Add Having condition. /// Condition column. /// Condition value. @@ -10565,7 +11049,7 @@ namespace DynamORM { return this.InternalHaving(column, value); } - + /// Add Having condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which @@ -10575,11 +11059,11 @@ namespace DynamORM { return this.InternalHaving(conditions, schema); } - + #endregion Having - + #region OrderBy - + /// /// Adds to the 'Order By' clause the contents obtained from from parsing the dynamic lambda expression given. It /// accepts a multipart column specification followed by an optional Ascending() or Descending() virtual methods @@ -10589,49 +11073,52 @@ namespace DynamORM /// The specification. /// The specification. /// This instance to permit chaining. - public virtual IDynamicSelectQueryBuilder OrderBy(Func fn, params Func[] func) + public virtual IDynamicSelectQueryBuilder OrderBy(Func fn, + params Func[] func) { if (fn == null) throw new ArgumentNullException("Array of specifications cannot be null."); - + int index = OrderByFunc(-1, fn); - + if (func != null) for (int i = 0; i < func.Length; i++) { Func f = func[i]; index = OrderByFunc(index, f); } - + return this; } - + private int OrderByFunc(int index, Func f) { index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - + using (DynamicParser parser = DynamicParser.Parse(f)) { object result = parser.Result; - if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - + if (result == null) + throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); + string main = null; bool ascending = true; - + if (result is int) main = result.ToString(); else if (result is string) { string[] parts = ((string)result).Split(' '); main = Database.StripName(parts.First()); - + int colNo; if (!Int32.TryParse(main, out colNo)) main = FixObjectName(main); - - ascending = parts.Length != 2 || parts.Last().ToUpper() == "ASCENDING" || parts.Last().ToUpper() == "ASC"; + + ascending = parts.Length != 2 || parts.Last().ToUpper() == "ASCENDING" || + parts.Last().ToUpper() == "ASC"; } else { @@ -10644,12 +11131,17 @@ namespace DynamORM { object[] args = node.Arguments; if (args != null && !(node.Host is DynamicParser.Node.Argument)) - throw new ArgumentException(string.Format("{0} must be a parameterless method, but found: {1}.", name, args.Sketch())); - else if ((args == null || args.Length != 1) && node.Host is DynamicParser.Node.Argument) - throw new ArgumentException(string.Format("{0} requires one numeric parameter, but found: {1}.", name, args.Sketch())); - + throw new ArgumentException(string.Format( + "{0} must be a parameterless method, but found: {1}.", name, + args.Sketch())); + else if ((args == null || args.Length != 1) && + node.Host is DynamicParser.Node.Argument) + throw new ArgumentException(string.Format( + "{0} requires one numeric parameter, but found: {1}.", name, + args.Sketch())); + ascending = (name == "ASCENDING" || name == "ASC") ? true : false; - + if (args != null && args.Length == 1) { int col = -1; @@ -10665,28 +11157,28 @@ namespace DynamORM else main = Parse(args[0], pars: Parameters); } - + result = node.Host; } } - + // Just parsing the contents... if (!(result is DynamicParser.Node.Argument)) main = Parse(result, pars: Parameters); } - + main = main.Validated("Order By"); main = string.Format("{0} {1}", main, ascending ? "ASC" : "DESC"); - + if (_orderby == null) _orderby = main; else _orderby = string.Format("{0}, {1}", _orderby, main); } - + return index; } - + /// Add select columns. /// Columns to order by. /// Builder instance. @@ -10697,10 +11189,10 @@ namespace DynamORM DynamicColumn col = columns[i]; OrderBy(x => col.ToSQLOrderByColumn(Database)); } - + return this; } - + /// Add select columns. /// Columns to order by. /// Column format consist of Column Name and @@ -10710,11 +11202,11 @@ namespace DynamORM { return OrderByColumn(columns.Select(c => DynamicColumn.ParseOrderByColumn(c)).ToArray()); } - + #endregion OrderBy - + #region Top/Limit/Offset/Distinct - + /// Set top if database support it. /// How many objects select. /// Builder instance. @@ -10722,34 +11214,38 @@ namespace DynamORM { return Limit(top); } - + /// Set top if database support it. /// How many objects select. /// Builder instance. public virtual IDynamicSelectQueryBuilder Limit(int? limit) { - if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset && - (Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != DynamicDatabaseOptions.SupportFirstSkip && + 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; return this; } - + /// Set top if database support it. /// How many objects skip selecting. /// Builder instance. public virtual IDynamicSelectQueryBuilder Offset(int? offset) { - if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != DynamicDatabaseOptions.SupportLimitOffset && - (Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != DynamicDatabaseOptions.SupportFirstSkip) + if ((Database.Options & DynamicDatabaseOptions.SupportLimitOffset) != + DynamicDatabaseOptions.SupportLimitOffset && + (Database.Options & DynamicDatabaseOptions.SupportFirstSkip) != + DynamicDatabaseOptions.SupportFirstSkip) throw new NotSupportedException("Database doesn't support OFFSET clause."); - + _offset = offset; return this; } - + /// Set distinct mode. /// Distinct mode. /// Builder instance. @@ -10758,92 +11254,99 @@ namespace DynamORM _distinct = distinct; return this; } - + #endregion Top/Limit/Offset/Distinct - + #region Helpers - + private void ParseSelectAddColumn(string main, string alias, bool all) { // We annotate the aliases being conservative... main = main.Validated("Main"); - + ////if (alias != null && !main.ContainsAny(StringExtensions.InvalidMemberChars)) TableAliasList.Add(new KTableAlias(main, alias)); - + // If all columns are requested... if (all) main += ".*"; - + // We finally add the contents... string str = (alias == null || all) ? main : string.Format("{0} AS {1}", main, alias); _select = _select == null ? str : string.Format("{0}, {1}", _select, str); } - + private void ParseSelectNode(object result, ref string column, ref string alias, ref bool all) { string main = null; - + DynamicParser.Node node = (DynamicParser.Node)result; while (true) { // Support for the AS() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "AS") { if (alias != null) - throw new ArgumentException(string.Format("Alias '{0}' is already set when parsing '{1}'.", alias, result)); - + throw new ArgumentException( + string.Format("Alias '{0}' is already set when parsing '{1}'.", alias, result)); + object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args == null) throw new ArgumentNullException("arg", "AS() is not a parameterless method."); - + if (args.Length != 1) - throw new ArgumentException("AS() requires one and only one parameter: " + args.Sketch()); - + throw new ArgumentException( + "AS() requires one and only one parameter: " + args.Sketch()); + // Yes, we decorate columns alias = Parse(args[0], rawstr: true, decorate: true, isMultiPart: false).Validated("Alias"); - + node = node.Host; continue; } - + // Support for the ALL() virtual method... - if (node is DynamicParser.Node.Method && ((DynamicParser.Node.Method)node).Name.ToUpper() == "ALL") + if (node is DynamicParser.Node.Method && + ((DynamicParser.Node.Method)node).Name.ToUpper() == "ALL") { if (all) - throw new ArgumentException(string.Format("Flag to select all columns is already set when parsing '{0}'.", result)); - + throw new ArgumentException(string.Format( + "Flag to select all columns is already set when parsing '{0}'.", result)); + object[] args = ((DynamicParser.Node.Method)node).Arguments; - + if (args != null) - throw new ArgumentException("ALL() must be a parameterless virtual method, but found: " + args.Sketch()); - + throw new ArgumentException( + "ALL() must be a parameterless virtual method, but found: " + args.Sketch()); + all = true; - + node = node.Host; continue; } - + // Support for table and/or column specifications... if (node is DynamicParser.Node.GetMember) { if (main != null) - throw new ArgumentException(string.Format("Main '{0}' is already set when parsing '{1}'.", main, result)); - + throw new ArgumentException( + string.Format("Main '{0}' is already set when parsing '{1}'.", main, result)); + main = ((DynamicParser.Node.GetMember)node).Name; - + if (node.Host is DynamicParser.Node.GetMember) { // If leaf then decorate main = Database.DecorateName(main); - + // Supporting multipart specifications... node = node.Host; - + // Get table/alias name string table = ((DynamicParser.Node.GetMember)node).Name; bool isAlias = node.Host is DynamicParser.Node.Argument && IsTableAlias(table); - + if (isAlias) main = string.Format("{0}.{1}", table, main); else if (node.Host is DynamicParser.Node.GetMember) @@ -10859,7 +11362,7 @@ namespace DynamORM else if (node.Host is DynamicParser.Node.Argument) { string table = ((DynamicParser.Node.Argument)node.Host).Name; - + if (IsTableAlias(table)) main = string.Format("{0}.{1}", table, Database.DecorateName(main)); else if (!IsTableAlias(main)) @@ -10867,74 +11370,78 @@ namespace DynamORM } else if (!(node.Host is DynamicParser.Node.Argument && IsTableAlias(main))) main = Database.DecorateName(main); - + node = node.Host; - + continue; } - + // Support for generic sources... if (node is DynamicParser.Node.Invoke) { if (main != null) - throw new ArgumentException(string.Format("Main '{0}' is already set when parsing '{1}'.", main, result)); - + throw new ArgumentException( + string.Format("Main '{0}' is already set when parsing '{1}'.", main, result)); + main = string.Format("{0}", Parse(node, rawstr: true, pars: Parameters)); - + node = node.Host; continue; } - + // Just finished the parsing... if (node is DynamicParser.Node.Argument) { if (string.IsNullOrEmpty(main) && IsTableAlias(node.Name)) main = node.Name; - + break; } - + // All others are assumed to be part of the main element... - if (main != null) throw new ArgumentException(string.Format("Main '{0}' is already set when parsing '{1}'.", main, result)); + if (main != null) + throw new ArgumentException(string.Format("Main '{0}' is already set when parsing '{1}'.", + main, result)); main = Parse(node, pars: Parameters); - + break; } - + column = main; } - + #endregion Helpers - + #region IExtendedDisposable - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public override void Dispose() { base.Dispose(); - + _select = _from = _join = _groupby = _orderby = null; } - + #endregion IExtendedDisposable } - + /// Update query builder. - internal class DynamicUpdateQueryBuilder : DynamicModifyBuilder, IDynamicUpdateQueryBuilder, DynamicQueryBuilder.IQueryWithWhere + internal class DynamicUpdateQueryBuilder : DynamicModifyBuilder, IDynamicUpdateQueryBuilder, + DynamicQueryBuilder.IQueryWithWhere { private string _columns; - + internal DynamicUpdateQueryBuilder(DynamicDatabase db) : base(db) { } - + public DynamicUpdateQueryBuilder(DynamicDatabase db, string tableName) : base(db, tableName) { } - + /// Generates the text this command will execute against the underlying database. /// The text to execute against the underlying database. /// This method must be override by derived classes. @@ -10942,14 +11449,16 @@ namespace DynamORM { ITableInfo info = Tables.Single(); return string.Format("UPDATE {0}{1} SET {2}{3}{4}", - string.IsNullOrEmpty(info.Owner) ? string.Empty : string.Format("{0}.", Database.DecorateName(info.Owner)), + string.IsNullOrEmpty(info.Owner) + ? string.Empty + : string.Format("{0}.", Database.DecorateName(info.Owner)), Database.DecorateName(info.Name), _columns, string.IsNullOrEmpty(WhereCondition) ? string.Empty : " WHERE ", WhereCondition); } - + #region Update - + /// Add update value or where condition using schema. /// Update or where column name. /// Column value. @@ -10957,18 +11466,19 @@ namespace DynamORM public virtual IDynamicUpdateQueryBuilder Update(string column, object value) { DynamicSchemaColumn? col = GetColumnFromSchema(column); - + if (!col.HasValue && SupportSchema) - throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", column)); - + throw new InvalidOperationException( + string.Format("Column '{0}' not found in schema, can't use universal approach.", column)); + if (col.HasValue && col.Value.IsKey) Where(column, value); else Values(column, value); - + return this; } - + /// Add update values and where condition columns using schema. /// Set values or conditions as properties and values of an object. /// Builder instance. @@ -10977,58 +11487,61 @@ namespace DynamORM if (conditions is DynamicColumn) { DynamicColumn column = (DynamicColumn)conditions; - + DynamicSchemaColumn? col = column.Schema ?? GetColumnFromSchema(column.ColumnName); - + if (!col.HasValue && SupportSchema) - throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", column)); - + throw new InvalidOperationException( + string.Format("Column '{0}' not found in schema, can't use universal approach.", + column)); + if (col.HasValue && col.Value.IsKey) Where(column); else Values(column.ColumnName, column.Value); - + return this; } - + IDictionary dict = conditions.ToDictionary(); DynamicTypeMap mapper = DynamicMapperCache.GetMapper(conditions.GetType()); - + foreach (KeyValuePair con in dict) { if (mapper.Ignored.Contains(con.Key)) continue; - + string colName = mapper != null ? mapper.PropertyMap.TryGetValue(con.Key) ?? con.Key : con.Key; DynamicSchemaColumn? col = GetColumnFromSchema(colName); - + if (!col.HasValue && SupportSchema) - throw new InvalidOperationException(string.Format("Column '{0}' not found in schema, can't use universal approach.", colName)); - + throw new InvalidOperationException(string.Format( + "Column '{0}' not found in schema, can't use universal approach.", colName)); + if (col.HasValue) { colName = col.Value.Name; - + if (col.Value.IsKey) { Where(colName, con.Value); - + continue; } } - + DynamicPropertyInvoker propMap = mapper.ColumnsMap.TryGetValue(colName.ToLower()); if (propMap == null || propMap.Column == null || !propMap.Column.IsNoUpdate) Values(colName, con.Value); } - + return this; } - + #endregion Update - + #region Values - + /// /// Specifies the columns to update using the dynamic lambda expressions given. Each expression correspond to one /// column, and can: @@ -11041,36 +11554,37 @@ namespace DynamORM { if (func == null) throw new ArgumentNullException("Array of specifications cannot be null."); - + int index = -1; foreach (Func f in func) { index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - + object result = null; - + using (DynamicParser p = DynamicParser.Parse(f)) { result = p.Result; - + if (result == null) - throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); - + throw new ArgumentException( + string.Format("Specification #{0} resolves to null.", index)); + string main = null; string value = null; string str = null; - + // When 'x => x.Table.Column = value' or 'x => x.Column = value'... if (result is DynamicParser.Node.SetMember) { DynamicParser.Node.SetMember node = (DynamicParser.Node.SetMember)result; - + DynamicSchemaColumn? col = GetColumnFromSchema(node.Name); main = Database.DecorateName(node.Name); value = Parse(node.Value, ref col, pars: Parameters, nulls: true); - + str = string.Format("{0} = {1}", main, value); _columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str); continue; @@ -11080,7 +11594,7 @@ namespace DynamORM Values(result); continue; } - + // Other specifications are considered invalid... string err = string.Format("Specification '{0}' is invalid.", result); str = Parse(result); @@ -11088,10 +11602,10 @@ namespace DynamORM throw new ArgumentException(err); } } - + return this; } - + /// Add insert fields. /// Insert column. /// Insert value. @@ -11101,20 +11615,20 @@ namespace DynamORM if (value is DynamicColumn) { DynamicColumn v = (DynamicColumn)value; - + if (string.IsNullOrEmpty(v.ColumnName)) v.ColumnName = column; - + return Values(v); } - + return Values(new DynamicColumn { ColumnName = column, Value = value, }); } - + /// Add insert fields. /// Set insert value as properties and values of an object. /// Builder instance. @@ -11124,19 +11638,19 @@ namespace DynamORM { DynamicColumn column = (DynamicColumn)o; DynamicSchemaColumn? col = column.Schema ?? GetColumnFromSchema(column.ColumnName); - + string main = FixObjectName(column.ColumnName, onlyColumn: true); string value = Parse(column.Value, ref col, pars: Parameters, nulls: true); - + string str = string.Format("{0} = {1}", main, value); _columns = _columns == null ? str : string.Format("{0}, {1}", _columns, str); - + return this; } - + IDictionary dict = o.ToDictionary(); DynamicTypeMap mapper = DynamicMapperCache.GetMapper(o.GetType()); - + if (mapper != null) { foreach (KeyValuePair con in dict) @@ -11146,14 +11660,14 @@ namespace DynamORM else foreach (KeyValuePair con in dict) Values(con.Key, con.Value); - + return this; } - + #endregion Values - + #region Where - + /// /// Adds to the 'Where' clause the contents obtained from parsing the dynamic lambda expression given. The condition /// is parsed to the appropriate syntax, where the specific customs virtual methods supported by the parser are used @@ -11168,7 +11682,7 @@ namespace DynamORM { return this.InternalWhere(func); } - + /// Add where condition. /// Condition column with operator and value. /// Builder instance. @@ -11176,17 +11690,18 @@ namespace DynamORM { return this.InternalWhere(column); } - + /// Add where condition. /// Condition column. /// Condition operator. /// Condition value. /// Builder instance. - public virtual IDynamicUpdateQueryBuilder Where(string column, DynamicColumn.CompareOperator op, object value) + public virtual IDynamicUpdateQueryBuilder Where(string column, DynamicColumn.CompareOperator op, + object value) { return this.InternalWhere(column, op, value); } - + /// Add where condition. /// Condition column. /// Condition value. @@ -11195,7 +11710,7 @@ namespace DynamORM { return this.InternalWhere(column, value); } - + /// Add where condition. /// Set conditions as properties and values of an object. /// If true use schema to determine key columns and ignore those which @@ -11205,27 +11720,27 @@ namespace DynamORM { return this.InternalWhere(conditions, schema); } - + #endregion Where - + #region IExtendedDisposable - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public override void Dispose() { base.Dispose(); - + _columns = null; } - + #endregion IExtendedDisposable } } } namespace Helpers - { + { /// Defines methods to support the comparison of collections for equality. /// The type of collection to compare. public class CollectionComparer : IEqualityComparer> @@ -11238,7 +11753,7 @@ namespace DynamORM { return Equals(first, second); } - + /// Returns a hash code for the specified object. /// The enumerable for which a hash code is to be returned. /// A hash code for the specified object. @@ -11246,20 +11761,20 @@ namespace DynamORM { return GetHashCode(enumerable); } - + /// Returns a hash code for the specified object. /// The enumerable for which a hash code is to be returned. /// A hash code for the specified object. public static int GetHashCode(IEnumerable enumerable) { int hash = 17; - + foreach (T val in enumerable.OrderBy(x => x)) hash = (hash * 23) + val.GetHashCode(); - + return hash; } - + /// Determines whether the specified objects are equal. /// The first object of type T to compare. /// The second object of type T to compare. @@ -11268,42 +11783,42 @@ namespace DynamORM { if ((first == null) != (second == null)) return false; - + if (!object.ReferenceEquals(first, second) && (first != null)) { if (first.Count() != second.Count()) return false; - + if ((first.Count() != 0) && HaveMismatchedElement(first, second)) return false; } - + return true; } - + private static bool HaveMismatchedElement(IEnumerable first, IEnumerable second) { int firstCount; int secondCount; - + Dictionary firstElementCounts = GetElementCounts(first, out firstCount); Dictionary secondElementCounts = GetElementCounts(second, out secondCount); - + if (firstCount != secondCount) return true; - + foreach (KeyValuePair kvp in firstElementCounts) if (kvp.Value != (secondElementCounts.TryGetNullable(kvp.Key) ?? 0)) return true; - + return false; } - + private static Dictionary GetElementCounts(IEnumerable enumerable, out int nullCount) { Dictionary dictionary = new Dictionary(); nullCount = 0; - + foreach (T element in enumerable) { if (element == null) @@ -11314,11 +11829,11 @@ namespace DynamORM dictionary[element] = ++count; } } - + return dictionary; } } - + /// Extensions for data reader handling. public static class DataReaderExtensions { @@ -11331,66 +11846,71 @@ namespace DynamORM { DataTable schemaTable = r.GetSchemaTable(); DataTable resultTable = new DataTable(name, nameSpace); - + foreach (DataRow col in schemaTable.Rows) { dynamic c = col.RowToDynamicUpper(); - + DataColumn dataColumn = new DataColumn(); dataColumn.ColumnName = c.COLUMNNAME; dataColumn.DataType = (Type)c.DATATYPE; dataColumn.ReadOnly = true; dataColumn.Unique = c.ISUNIQUE; - + resultTable.Columns.Add(dataColumn); } - + while (r.Read()) { DataRow row = resultTable.NewRow(); for (int i = 0; i < resultTable.Columns.Count; i++) row[i] = r[i]; - + resultTable.Rows.Add(row); } - + return resultTable; } } - + /// Framework detection and specific implementations. public static class FrameworkTools { #region Mono or .NET Framework detection - + /// This is pretty simple trick. private static bool _isMono = Type.GetType("Mono.Runtime") != null; - + /// Gets a value indicating whether application is running under mono runtime. - public static bool IsMono { get { return _isMono; } } - + public static bool IsMono + { + get { return _isMono; } + } + #endregion Mono or .NET Framework detection - + static FrameworkTools() { _frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter(); } - + #region GetGenericTypeArguments - + private static Func> _frameworkTypeArgumentsGetter = null; - + private static Func> CreateTypeArgumentsGetter() { // HACK: Creating binders assuming types are correct... this may fail. if (IsMono) { - Type binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder"); - + Type binderType = + typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType( + "Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder"); + if (binderType != null) { ParameterExpression param = Expression.Parameter(typeof(InvokeMemberBinder), "o"); - + try { return Expression.Lambda>>( @@ -11402,12 +11922,12 @@ namespace DynamORM catch { } - + PropertyInfo prop = binderType.GetProperty("TypeArguments"); - + if (!prop.CanRead) return null; - + return Expression.Lambda>>( Expression.TypeAs( Expression.Property( @@ -11417,17 +11937,19 @@ namespace DynamORM } else { - Type inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); - + Type inter = + typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType( + "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); + if (inter != null) { PropertyInfo prop = inter.GetProperty("TypeArguments"); - + if (!prop.CanRead) return null; - + ParameterExpression objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o"); - + return Expression.Lambda>>( Expression.TypeAs( Expression.Property( @@ -11435,10 +11957,10 @@ namespace DynamORM typeof(IList)), objParm).Compile(); } } - + return null; } - + /// Extension method allowing to easily extract generic type /// arguments from assuming that it /// inherits from @@ -11455,23 +11977,23 @@ namespace DynamORM // First try to use delegate if exist if (_frameworkTypeArgumentsGetter != null) return _frameworkTypeArgumentsGetter(binder); - + if (_isMono) { // HACK: Using Reflection // In mono this is trivial. - + // First we get field info. FieldInfo field = binder.GetType().GetField("typeArguments", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - + // If this was a success get and return it's value if (field != null) return field.GetValue(binder) as IList; else { PropertyInfo prop = binder.GetType().GetProperty("TypeArguments"); - + // If we have a property, return it's value if (prop != null) return prop.GetValue(binder, null) as IList; @@ -11481,28 +12003,29 @@ namespace DynamORM { // HACK: Using Reflection // In this case, we need more aerobic :D - + // First, get the interface - Type inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); - + Type inter = binder.GetType() + .GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder"); + if (inter != null) { // Now get property. PropertyInfo prop = inter.GetProperty("TypeArguments"); - + // If we have a property, return it's value if (prop != null) return prop.GetValue(binder, null) as IList; } } - + // Sadly return null if failed. return null; } - + #endregion GetGenericTypeArguments } - + /// Extends interface. public interface IExtendedDisposable : IDisposable { @@ -11514,7 +12037,7 @@ namespace DynamORM /// bool IsDisposed { get; } } - + /// Extends interface. public interface IFinalizerDisposable : IExtendedDisposable { @@ -11523,7 +12046,7 @@ namespace DynamORM /// If set to true dispose object. void Dispose(bool disposing); } - + public static class ReaderExtensions { public static bool? GetBooleanIfNotNull(this IDataReader r, string name, bool? def = null) @@ -11531,119 +12054,119 @@ namespace DynamORM var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetBoolean(ord); } - + public static byte? GetByteIfNotNull(this IDataReader r, string name, byte? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetByte(ord); } - + public static char? GetCharIfNotNull(this IDataReader r, string name, char? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetChar(ord); } - + public static DateTime? GetDateTimeIfNotNull(this IDataReader r, string name, DateTime? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetDateTime(ord); } - + public static decimal? GetDecimalIfNotNull(this IDataReader r, string name, decimal? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetDecimal(ord); } - + public static double? GetDoubleIfNotNull(this IDataReader r, string name, double? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetDouble(ord); } - + public static float? GetFloatIfNotNull(this IDataReader r, string name, float? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetFloat(ord); } - + public static Guid? GetGuidIfNotNull(this IDataReader r, string name, Guid? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetGuid(ord); } - + public static short? GetInt16IfNotNull(this IDataReader r, string name, short? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetInt16(ord); } - + public static int? GetInt32IfNotNull(this IDataReader r, string name, int? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetInt32(ord); } - + public static long? GetInt64IfNotNull(this IDataReader r, string name, long? def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetInt64(ord); } - + public static string GetStringIfNotNull(this IDataReader r, string name, string def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetString(ord); } - + public static object GetValueIfNotNull(this IDataReader r, string name, object def = null) { var ord = r.GetOrdinal(name); if (r.IsDBNull(ord)) return def; - + return r.GetValue(ord); } } - + /// Class containing useful string extensions. internal static class StringExtensions { @@ -11652,20 +12175,20 @@ namespace DynamORM InvalidMultipartMemberChars = _InvalidMultipartMemberChars.ToCharArray(); InvalidMemberChars = _InvalidMemberChars.ToCharArray(); } - + private static readonly string _InvalidMultipartMemberChars = " +-*/^%[]{}()!\"\\&=?¿"; private static readonly string _InvalidMemberChars = "." + _InvalidMultipartMemberChars; - + /// /// Gets an array with some invalid characters that cannot be used with multipart names for class members. /// public static char[] InvalidMultipartMemberChars { get; private set; } - + /// /// Gets an array with some invalid characters that cannot be used with names for class members. /// public static char[] InvalidMemberChars { get; private set; } - + /// /// Provides with an alternate and generic way to obtain an alternate string representation for this instance, /// applying the following rules: @@ -11687,34 +12210,37 @@ namespace DynamORM { if (obj == null) return nullString; if (obj is string) return (string)obj; - + Type type = obj.GetType(); if (type.IsEnum) return obj.ToString(); - + // If the ToString() method has been overriden (by the type itself, or by its parents), let's use it... MethodInfo method = type.GetMethod("ToString", Type.EmptyTypes); if (method.DeclaringType != typeof(object)) return obj.ToString(); - + // For alll other cases... StringBuilder sb = new StringBuilder(); bool first = true; - + // Dictionaries... if (obj is IDictionary) { if (brackets == null || brackets.Length < 2) brackets = "[]".ToCharArray(); - - sb.AppendFormat("{0}", brackets[0]); first = true; foreach (DictionaryEntry kvp in (IDictionary)obj) + + sb.AppendFormat("{0}", brackets[0]); + first = true; + foreach (DictionaryEntry kvp in (IDictionary)obj) { - if (!first) sb.Append(", "); else first = false; + if (!first) sb.Append(", "); + else first = false; sb.AppendFormat("'{0}'='{1}'", kvp.Key.Sketch(), kvp.Value.Sketch()); } - + sb.AppendFormat("{0}", brackets[1]); return sb.ToString(); } - + // IEnumerables... IEnumerator ator = null; if (obj is IEnumerable) @@ -11725,41 +12251,45 @@ namespace DynamORM if (method != null) ator = (IEnumerator)method.Invoke(obj, null); } - + if (ator != null) { if (brackets == null || brackets.Length < 2) brackets = "[]".ToCharArray(); - sb.AppendFormat("{0}", brackets[0]); first = true; while (ator.MoveNext()) + sb.AppendFormat("{0}", brackets[0]); + first = true; + while (ator.MoveNext()) { - if (!first) sb.Append(", "); else first = false; + if (!first) sb.Append(", "); + else first = false; sb.AppendFormat("{0}", ator.Current.Sketch()); } - + sb.AppendFormat("{0}", brackets[1]); - + if (ator is IDisposable) ((IDisposable)ator).Dispose(); - + return sb.ToString(); } - + // As a last resort, using the public properties (or fields if needed, or type name)... BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy; PropertyInfo[] props = type.GetProperties(flags); FieldInfo[] infos = type.GetFields(flags); - + if (props.Length == 0 && infos.Length == 0) sb.Append(type.FullName); // Fallback if needed else { if (brackets == null || brackets.Length < 2) brackets = "{}".ToCharArray(); sb.AppendFormat("{0}", brackets[0]); first = true; - + if (props.Length != 0) { foreach (PropertyInfo prop in props) { - if (!first) sb.Append(", "); else first = false; + if (!first) sb.Append(", "); + else first = false; sb.AppendFormat("{0}='{1}'", prop.Name, prop.GetValue(obj, null).Sketch()); } } @@ -11769,19 +12299,20 @@ namespace DynamORM { foreach (FieldInfo info in infos) { - if (!first) sb.Append(", "); else first = false; + if (!first) sb.Append(", "); + else first = false; sb.AppendFormat("{0}='{1}'", info.Name, info.GetValue(obj).Sketch()); } } } - + sb.AppendFormat("{0}", brackets[1]); } - + // And returning... return sb.ToString(); } - + /// /// Returns true if the target string contains any of the characters given. /// @@ -11791,13 +12322,14 @@ namespace DynamORM public static bool ContainsAny(this string source, char[] items) { if (source == null) throw new ArgumentNullException("source", "Source string cannot be null."); - if (items == null) throw new ArgumentNullException("items", "Array of characters to test cannot be null."); - + if (items == null) + throw new ArgumentNullException("items", "Array of characters to test cannot be null."); + if (items.Length == 0) return false; // No characters to validate int ix = source.IndexOfAny(items); return ix >= 0 ? true : false; } - + /// /// Returns a new validated string using the rules given. /// @@ -11825,14 +12357,14 @@ namespace DynamORM { // Assuring a valid descriptor... if (string.IsNullOrWhiteSpace(desc)) desc = "Source"; - + // Validating if null sources are accepted... if (source == null) { if (!canbeNull) throw new ArgumentNullException(desc, string.Format("{0} cannot be null.", desc)); return null; } - + // Trimming if needed... if (trim && !(trimStart || trimEnd)) source = source.Trim(); else @@ -11840,47 +12372,55 @@ namespace DynamORM if (trimStart) source = source.TrimStart(' '); if (trimEnd) source = source.TrimEnd(' '); } - + // Adjusting lenght... if (minLen > 0) { if (padLeft != '\0') source = source.PadLeft(minLen, padLeft); if (padRight != '\0') source = source.PadRight(minLen, padRight); } - + if (maxLen > 0) { if (padLeft != '\0') source = source.PadLeft(maxLen, padLeft); if (padRight != '\0') source = source.PadRight(maxLen, padRight); } - + // Validating emptyness and lenghts... if (source.Length == 0) { if (!canbeEmpty) throw new ArgumentException(string.Format("{0} cannot be empty.", desc)); return string.Empty; } - - if (minLen >= 0 && source.Length < minLen) throw new ArgumentException(string.Format("Lenght of {0} '{1}' is lower than '{2}'.", desc, source, minLen)); - if (maxLen >= 0 && source.Length > maxLen) throw new ArgumentException(string.Format("Lenght of {0} '{1}' is bigger than '{2}'.", desc, source, maxLen)); - + + if (minLen >= 0 && source.Length < minLen) + throw new ArgumentException(string.Format("Lenght of {0} '{1}' is lower than '{2}'.", desc, source, + minLen)); + if (maxLen >= 0 && source.Length > maxLen) + throw new ArgumentException(string.Format("Lenght of {0} '{1}' is bigger than '{2}'.", desc, source, + maxLen)); + // Checking invalid chars... if (invalidChars != null) { int n = source.IndexOfAny(invalidChars); - if (n >= 0) throw new ArgumentException(string.Format("Invalid character '{0}' found in {1} '{2}'.", source[n], desc, source)); + if (n >= 0) + throw new ArgumentException(string.Format("Invalid character '{0}' found in {1} '{2}'.", + source[n], desc, source)); } - + // Checking valid chars... if (validChars != null) { int n = validChars.ToString().IndexOfAny(source.ToCharArray()); - if (n >= 0) throw new ArgumentException(string.Format("Invalid character '{0}' found in {1} '{2}'.", validChars.ToString()[n], desc, source)); + if (n >= 0) + throw new ArgumentException(string.Format("Invalid character '{0}' found in {1} '{2}'.", + validChars.ToString()[n], desc, source)); } - + return source; } - + /// /// Splits the given string with the 'something AS alias' format, returning a tuple containing its 'something' and 'alias' parts. /// If no alias is detected, then its component in the tuple returned is null and all the contents from the source @@ -11891,11 +12431,11 @@ namespace DynamORM public static Tuple SplitSomethingAndAlias(this string source) { source = source.Validated("[Something AS Alias]"); - + string something = null; string alias = null; int n = source.LastIndexOf(" AS ", StringComparison.OrdinalIgnoreCase); - + if (n < 0) something = source; else @@ -11903,44 +12443,46 @@ namespace DynamORM something = source.Substring(0, n); alias = source.Substring(n + 4); } - + return new Tuple(something, alias); } - + /// Allows to replace parameters inside of string. /// String containing parameters in format [$ParameterName]. /// Function that should return value that will be placed in string in place of placed parameter. /// Prefix of the parameter. This value can't be null or empty, default value [$. /// Suffix of the parameter. This value can't be null or empty, default value ]. /// Parsed string. - public static string FillStringWithVariables(this string stringToFill, Func getValue, string prefix = "[$", string sufix = "]") + public static string FillStringWithVariables(this string stringToFill, Func getValue, + string prefix = "[$", string sufix = "]") { int startPos = 0, endPos = 0; prefix.Validated(); sufix.Validated(); - + startPos = stringToFill.IndexOf(prefix, startPos); while (startPos >= 0) { endPos = stringToFill.IndexOf(sufix, startPos + prefix.Length); int nextStartPos = stringToFill.IndexOf(prefix, startPos + prefix.Length); - + if (endPos > startPos + prefix.Length + 1 && (nextStartPos > endPos || nextStartPos == -1)) { - string paramName = stringToFill.Substring(startPos + prefix.Length, endPos - (startPos + prefix.Length)); - + string paramName = stringToFill.Substring(startPos + prefix.Length, + endPos - (startPos + prefix.Length)); + stringToFill = stringToFill .Remove(startPos, (endPos - startPos) + sufix.Length) .Insert(startPos, getValue(paramName)); } - + startPos = stringToFill.IndexOf(prefix, startPos + prefix.Length); } - + return stringToFill; } } - + /// Class contains unclassified extensions. internal static class UnclassifiedExtensions { @@ -11959,10 +12501,9 @@ namespace DynamORM /// public static R NullOr(this T obj, Func func, R elseValue = default(R)) where T : class { - return obj != null && obj != DBNull.Value ? - func(obj) : elseValue; + return obj != null && obj != DBNull.Value ? func(obj) : elseValue; } - + /// Easy way to use conditional value. /// Includes . /// Input object type to check. @@ -11979,11 +12520,10 @@ namespace DynamORM public static R NullOrFn(this T obj, Func func, Func elseFunc = null) where T : class { // Old if to avoid recurency. - return obj != null && obj != DBNull.Value ? - func(obj) : elseFunc != null ? elseFunc() : default(R); + return obj != null && obj != DBNull.Value ? func(obj) : elseFunc != null ? elseFunc() : default(R); } - - #if !NET6_0_OR_GREATER + +#if !NET6_0_OR_GREATER /// Simple distinct by selector extension. /// The enumerator of elements distinct by specified selector. /// Source collection. @@ -11997,18 +12537,18 @@ namespace DynamORM if (seenKeys.Add(keySelector(element))) yield return element; } - #endif +#endif } namespace Dynamics - { + { /// /// Class able to parse dynamic lambda expressions. Allows to create dynamic logic. /// public class DynamicParser : IExtendedDisposable { #region Node - + /// /// Generic bindable operation where some of its operands is a dynamic argument, or a dynamic member or /// a method of that argument. @@ -12017,9 +12557,9 @@ namespace DynamORM public class Node : IDynamicMetaObjectProvider, IFinalizerDisposable, ISerializable { private DynamicParser _parser = null; - + #region MetaNode - + /// /// Represents the dynamic binding and a binding logic of /// an object participating in the dynamic binding. @@ -12036,20 +12576,21 @@ namespace DynamORM : base(parameter, rest, value) { } - + // Func was cool but caused memory leaks private DynamicMetaObject GetBinder(Node node) { Node o = (Node)this.Value; node.Parser = o.Parser; o.Parser.Last = node; - + ParameterExpression p = Expression.Variable(typeof(Node), "ret"); - BlockExpression exp = Expression.Block(new ParameterExpression[] { p }, Expression.Assign(p, Expression.Constant(node))); - + BlockExpression exp = Expression.Block(new ParameterExpression[] { p }, + Expression.Assign(p, Expression.Constant(node))); + return new MetaNode(exp, this.Restrictions, node); } - + /// /// Performs the binding of the dynamic get member operation. /// @@ -12061,7 +12602,7 @@ namespace DynamORM { return GetBinder(new GetMember((Node)this.Value, binder.Name)); } - + /// /// Performs the binding of the dynamic set member operation. /// @@ -12074,7 +12615,7 @@ namespace DynamORM { return GetBinder(new SetMember((Node)this.Value, binder.Name, value.Value)); } - + /// /// Performs the binding of the dynamic get index operation. /// @@ -12083,11 +12624,12 @@ namespace DynamORM /// /// The new representing the result of the binding. /// - public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) + public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, + DynamicMetaObject[] indexes) { return GetBinder(new GetIndex((Node)this.Value, MetaList2List(indexes))); } - + /// /// Performs the binding of the dynamic set index operation. /// @@ -12097,11 +12639,12 @@ namespace DynamORM /// /// The new representing the result of the binding. /// - public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) + public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, + DynamicMetaObject[] indexes, DynamicMetaObject value) { return GetBinder(new SetIndex((Node)this.Value, MetaList2List(indexes), value.Value)); } - + /// /// Performs the binding of the dynamic invoke operation. /// @@ -12114,7 +12657,7 @@ namespace DynamORM { return GetBinder(new Invoke((Node)this.Value, MetaList2List(args))); } - + /// /// Performs the binding of the dynamic invoke member operation. /// @@ -12123,11 +12666,12 @@ namespace DynamORM /// /// The new representing the result of the binding. /// - public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) + public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, + DynamicMetaObject[] args) { return GetBinder(new Method((Node)this.Value, binder.Name, MetaList2List(args))); } - + /// /// Performs the binding of the dynamic binary operation. /// @@ -12136,11 +12680,12 @@ namespace DynamORM /// /// The new representing the result of the binding. /// - public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) + public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, + DynamicMetaObject arg) { return GetBinder(new Binary((Node)this.Value, binder.Operation, arg.Value)); } - + /// /// Performs the binding of the dynamic unary operation. /// @@ -12153,20 +12698,22 @@ namespace DynamORM Node o = (Node)this.Value; Unary node = new Unary(o, binder.Operation) { Parser = o.Parser }; o.Parser.Last = node; - + // If operation is 'IsTrue' or 'IsFalse', we will return false to keep the engine working... object ret = node; if (binder.Operation == ExpressionType.IsTrue) ret = (object)false; if (binder.Operation == ExpressionType.IsFalse) ret = (object)false; - - ParameterExpression p = Expression.Variable(ret.GetType(), "ret"); // the type is now obtained from "ret" + + ParameterExpression + p = Expression.Variable(ret.GetType(), "ret"); // the type is now obtained from "ret" BlockExpression exp = Expression.Block( new ParameterExpression[] { p }, - Expression.Assign(p, Expression.Constant(ret))); // the expression is now obtained from "ret" - + Expression.Assign(p, + Expression.Constant(ret))); // the expression is now obtained from "ret" + return new MetaNode(exp, this.Restrictions, node); } - + /// /// Performs the binding of the dynamic conversion operation. /// @@ -12179,11 +12726,11 @@ namespace DynamORM Node o = (Node)this.Value; Convert node = new Convert(o, binder.ReturnType) { Parser = o.Parser }; o.Parser.Last = node; - + // Reducing the object to return if this is an assignment node... object ret = o; bool done = false; - + while (!done) { if (ret is SetMember) @@ -12193,7 +12740,7 @@ namespace DynamORM else done = true; } - + // Creating an instance... if (binder.ReturnType == typeof(string)) ret = ret.ToString(); else @@ -12203,7 +12750,8 @@ namespace DynamORM if (binder.ReturnType.IsNullableType()) ret = null; // to avoid cast exceptions else - ret = Activator.CreateInstance(binder.ReturnType, true); // true to allow non-public ctor as well + ret = Activator.CreateInstance(binder.ReturnType, + true); // true to allow non-public ctor as well } catch { @@ -12211,31 +12759,32 @@ namespace DynamORM ret = new object(); } } - + ParameterExpression p = Expression.Variable(binder.ReturnType, "ret"); BlockExpression exp = Expression.Block( new ParameterExpression[] { p }, - Expression.Assign(p, Expression.Constant(ret, binder.ReturnType))); // specifying binder.ReturnType - + Expression.Assign(p, + Expression.Constant(ret, binder.ReturnType))); // specifying binder.ReturnType + return new MetaNode(exp, this.Restrictions, node); } - + private static object[] MetaList2List(DynamicMetaObject[] metaObjects) { if (metaObjects == null) return null; - + object[] list = new object[metaObjects.Length]; for (int i = 0; i < metaObjects.Length; i++) list[i] = metaObjects[i].Value; - + return list; } } - + #endregion MetaNode - + #region Argument - + /// /// Describe a dynamic argument used in a dynamic lambda expression. /// @@ -12250,7 +12799,7 @@ namespace DynamORM : base(name) { } - + /// /// Initializes a new instance of the class. /// @@ -12260,7 +12809,7 @@ namespace DynamORM : base(info, context) { } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -12270,11 +12819,11 @@ namespace DynamORM return Name; } } - + #endregion Argument - + #region GetMember - + /// /// Describe a 'get member' operation, as in 'x => x.Member'. /// @@ -12290,7 +12839,7 @@ namespace DynamORM : base(host, name) { } - + /// /// Initializes a new instance of the class. /// @@ -12300,7 +12849,7 @@ namespace DynamORM : base(info, context) { } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -12310,11 +12859,11 @@ namespace DynamORM return string.Format("{0}.{1}", Host.Sketch(), Name.Sketch()); } } - + #endregion GetMember - + #region SetMember - + /// /// Describe a 'set member' operation, as in 'x => x.Member = y'. /// @@ -12326,7 +12875,7 @@ namespace DynamORM /// assigned to this instance, or if this instance is disposed. /// public object Value { get; private set; } - + /// /// Initializes a new instance of the class. /// @@ -12338,7 +12887,7 @@ namespace DynamORM { Value = value; } - + /// /// Initializes a new instance of the class. /// @@ -12350,7 +12899,7 @@ namespace DynamORM string type = info.GetString("MemberType"); Value = type == "NULL" ? null : info.GetValue("MemberValue", Type.GetType(type)); } - + /// /// Gets the object data. /// @@ -12361,10 +12910,10 @@ namespace DynamORM info.AddValue("MemberType", Value == null ? "NULL" : Value.GetType().AssemblyQualifiedName); if (Value != null) info.AddValue("MemberValue", Value); - + base.GetObjectData(info, context); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() @@ -12373,7 +12922,7 @@ namespace DynamORM return "{DynamicParser::Node::SetMember::Disposed}"; return string.Format("({0}.{1} = {2})", Host.Sketch(), Name.Sketch(), Value.Sketch()); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -12390,10 +12939,10 @@ namespace DynamORM { if (node.IsNodeAncestor(this)) node.Host = null; - + node.Dispose(disposing); } - + Value = null; } } @@ -12401,15 +12950,15 @@ namespace DynamORM { } } - + base.Dispose(disposing); } } - + #endregion SetMember - + #region GetIndex - + /// /// Describe a 'get indexed' operation, as in 'x => x.Member[...]'. /// @@ -12418,7 +12967,7 @@ namespace DynamORM { /// Gets the indexes. public object[] Indexes { get; internal set; } - + /// /// Initializes a new instance of the class. /// @@ -12433,10 +12982,10 @@ namespace DynamORM throw new ArgumentNullException("indexes", "Indexes array cannot be null."); if (indexes.Length == 0) throw new ArgumentException("Indexes array cannot be empty."); - + Indexes = indexes; } - + /// /// Initializes a new instance of the class. /// @@ -12446,18 +12995,21 @@ namespace DynamORM : base(info, context) { int count = (int)info.GetValue("IndexCount", typeof(int)); - + if (count != 0) { - Indexes = new object[count]; for (int i = 0; i < count; i++) + Indexes = new object[count]; + for (int i = 0; i < count; i++) { string typeName = info.GetString("IndexType" + i); - object obj = typeName == "NULL" ? null : info.GetValue("IndexValue" + i, Type.GetType(typeName)); + object obj = typeName == "NULL" + ? null + : info.GetValue("IndexValue" + i, Type.GetType(typeName)); Indexes[i] = obj; } } } - + /// /// Gets the object data. /// @@ -12465,26 +13017,29 @@ namespace DynamORM /// The context. public override void GetObjectData(SerializationInfo info, StreamingContext context) { - int count = Indexes == null ? 0 : Indexes.Length; info.AddValue("IndexCount", count); + int count = Indexes == null ? 0 : Indexes.Length; + info.AddValue("IndexCount", count); for (int i = 0; i < count; i++) { - info.AddValue("IndexType" + i, Indexes[i] == null ? "NULL" : Indexes[i].GetType().AssemblyQualifiedName); + info.AddValue("IndexType" + i, + Indexes[i] == null ? "NULL" : Indexes[i].GetType().AssemblyQualifiedName); if (Indexes[i] != null) info.AddValue("IndexValue" + i, Indexes[i]); } - + base.GetObjectData(info, context); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::GetIndex::Disposed}"; - - return string.Format("{0}{1}", Host.Sketch(), Indexes == null ? "[empty]" : Indexes.Sketch()); + + return string.Format("{0}{1}", Host.Sketch(), + Indexes == null ? "[empty]" : Indexes.Sketch()); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -12503,29 +13058,29 @@ namespace DynamORM { if (node.IsNodeAncestor(this)) node.Host = null; - + node.Dispose(disposing); } } - + Array.Clear(Indexes, 0, Indexes.Length); } } catch { } - + Indexes = null; } - + base.Dispose(disposing); } } - + #endregion GetIndex - + #region SetIndex - + /// /// Describe a 'set indexed' operation, as in 'x => x.Member[...] = Value'. /// @@ -12537,7 +13092,7 @@ namespace DynamORM /// assigned to this instance, or if this instance is disposed. /// public object Value { get; private set; } - + /// /// Initializes a new instance of the class. /// @@ -12549,7 +13104,7 @@ namespace DynamORM { Value = value; } - + /// /// Initializes a new instance of the class. /// @@ -12561,7 +13116,7 @@ namespace DynamORM string type = info.GetString("MemberType"); Value = type == "NULL" ? null : info.GetValue("MemberValue", Type.GetType(type)); } - + /// /// Gets the object data. /// @@ -12571,20 +13126,21 @@ namespace DynamORM { info.AddValue("MemberType", Value == null ? "NULL" : Value.GetType().AssemblyQualifiedName); if (Value != null) info.AddValue("MemberValue", Value); - + base.GetObjectData(info, context); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::SetIndex::Disposed}"; - - return string.Format("({0}{1} = {2})", Host.Sketch(), Indexes == null ? "[empty]" : Indexes.Sketch(), Value.Sketch()); + + return string.Format("({0}{1} = {2})", Host.Sketch(), + Indexes == null ? "[empty]" : Indexes.Sketch(), Value.Sketch()); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -12601,10 +13157,10 @@ namespace DynamORM { if (node.IsNodeAncestor(this)) node.Host = null; - + node.Dispose(disposing); } - + Value = null; } } @@ -12612,15 +13168,15 @@ namespace DynamORM { } } - + base.Dispose(disposing); } } - + #endregion SetIndex - + #region Invoke - + /// /// Describe a method invocation operation, as in 'x => x.Method(...)". /// @@ -12629,7 +13185,7 @@ namespace DynamORM { /// Gets the arguments. public object[] Arguments { get; internal set; } - + /// /// Initializes a new instance of the class. /// @@ -12640,7 +13196,7 @@ namespace DynamORM { Arguments = arguments == null || arguments.Length == 0 ? null : arguments; } - + /// /// Initializes a new instance of the class. /// @@ -12650,18 +13206,21 @@ namespace DynamORM : base(info, context) { int count = (int)info.GetValue("ArgumentCount", typeof(int)); - + if (count != 0) { - Arguments = new object[count]; for (int i = 0; i < count; i++) + Arguments = new object[count]; + for (int i = 0; i < count; i++) { string typeName = info.GetString("ArgumentType" + i); - object obj = typeName == "NULL" ? null : info.GetValue("ArgumentValue" + i, Type.GetType(typeName)); + object obj = typeName == "NULL" + ? null + : info.GetValue("ArgumentValue" + i, Type.GetType(typeName)); Arguments[i] = obj; } } } - + /// /// Gets the object data. /// @@ -12669,16 +13228,18 @@ namespace DynamORM /// The context. public override void GetObjectData(SerializationInfo info, StreamingContext context) { - int count = Arguments == null ? 0 : Arguments.Length; info.AddValue("ArgumentCount", count); + int count = Arguments == null ? 0 : Arguments.Length; + info.AddValue("ArgumentCount", count); for (int i = 0; i < count; i++) { - info.AddValue("ArgumentType" + i, Arguments[i] == null ? "NULL" : Arguments[i].GetType().AssemblyQualifiedName); + info.AddValue("ArgumentType" + i, + Arguments[i] == null ? "NULL" : Arguments[i].GetType().AssemblyQualifiedName); if (Arguments[i] != null) info.AddValue("ArgumentValue" + i, Arguments[i]); } - + base.GetObjectData(info, context); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -12697,39 +13258,40 @@ namespace DynamORM { if (node.IsNodeAncestor(this)) node.Host = null; - + node.Dispose(disposing); } } - + Array.Clear(Arguments, 0, Arguments.Length); } } catch { } - + Arguments = null; } - + base.Dispose(disposing); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::Invoke::Disposed}"; - - return string.Format("{0}{1}", Host.Sketch(), Arguments == null ? "()" : Arguments.Sketch(brackets: "()".ToCharArray())); + + return string.Format("{0}{1}", Host.Sketch(), + Arguments == null ? "()" : Arguments.Sketch(brackets: "()".ToCharArray())); } } - + #endregion Invoke - + #region Method - + /// /// Describe a method invocation operation, as in 'x => x.Method(...)". /// @@ -12738,7 +13300,7 @@ namespace DynamORM { /// Gets the arguments. public object[] Arguments { get; internal set; } - + /// /// Initializes a new instance of the class. /// @@ -12750,7 +13312,7 @@ namespace DynamORM { Arguments = arguments == null || arguments.Length == 0 ? null : arguments; } - + /// /// Initializes a new instance of the class. /// @@ -12760,18 +13322,21 @@ namespace DynamORM : base(info, context) { int count = (int)info.GetValue("ArgumentCount", typeof(int)); - + if (count != 0) { - Arguments = new object[count]; for (int i = 0; i < count; i++) + Arguments = new object[count]; + for (int i = 0; i < count; i++) { string typeName = info.GetString("ArgumentType" + i); - object obj = typeName == "NULL" ? null : info.GetValue("ArgumentValue" + i, Type.GetType(typeName)); + object obj = typeName == "NULL" + ? null + : info.GetValue("ArgumentValue" + i, Type.GetType(typeName)); Arguments[i] = obj; } } } - + /// /// Gets the object data. /// @@ -12779,26 +13344,29 @@ namespace DynamORM /// The context. public override void GetObjectData(SerializationInfo info, StreamingContext context) { - int count = Arguments == null ? 0 : Arguments.Length; info.AddValue("ArgumentCount", count); + int count = Arguments == null ? 0 : Arguments.Length; + info.AddValue("ArgumentCount", count); for (int i = 0; i < count; i++) { - info.AddValue("ArgumentType" + i, Arguments[i] == null ? "NULL" : Arguments[i].GetType().AssemblyQualifiedName); + info.AddValue("ArgumentType" + i, + Arguments[i] == null ? "NULL" : Arguments[i].GetType().AssemblyQualifiedName); if (Arguments[i] != null) info.AddValue("ArgumentValue" + i, Arguments[i]); } - + base.GetObjectData(info, context); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::Method::Disposed}"; - - return string.Format("{0}.{1}{2}", Host.Sketch(), Name.Sketch(), Arguments == null ? "()" : Arguments.Sketch(brackets: "()".ToCharArray())); + + return string.Format("{0}.{1}{2}", Host.Sketch(), Name.Sketch(), + Arguments == null ? "()" : Arguments.Sketch(brackets: "()".ToCharArray())); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -12817,29 +13385,29 @@ namespace DynamORM { if (node.IsNodeAncestor(this)) node.Host = null; - + node.Dispose(disposing); } } - + Array.Clear(Arguments, 0, Arguments.Length); } } catch { } - + Arguments = null; } - + base.Dispose(disposing); } } - + #endregion Method - + #region Binary - + /// /// Represents a binary operation between a dynamic element and an arbitrary object, including null ones, as in /// 'x => (x && null)'. The left operand must be an instance of , whereas the right one @@ -12850,13 +13418,16 @@ namespace DynamORM { /// Gets the operation. public ExpressionType Operation { get; private set; } - + /// Gets host of the . - public Node Left { get { return Host; } } - + public Node Left + { + get { return Host; } + } + /// Gets the right side value. public object Right { get; private set; } - + /// /// Initializes a new instance of the class. /// @@ -12869,7 +13440,7 @@ namespace DynamORM Operation = operation; Right = right; } - + /// /// Initializes a new instance of the class. /// @@ -12879,11 +13450,11 @@ namespace DynamORM : base(info, context) { Operation = (ExpressionType)info.GetValue("Operation", typeof(ExpressionType)); - + string type = info.GetString("RightType"); Right = type == "NULL" ? null : (Node)info.GetValue("RightItem", Type.GetType(type)); } - + /// /// Gets the object data. /// @@ -12892,31 +13463,31 @@ namespace DynamORM public override void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Operation", Operation); - + info.AddValue("RightType", Right == null ? "NULL" : Right.GetType().AssemblyQualifiedName); if (Right != null) info.AddValue("RightItem", Right); - + base.GetObjectData(info, context); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::Binary::Disposed}"; - + return string.Format("({0} {1} {2})", Host.Sketch(), Operation, Right.Sketch()); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. public override void Dispose(bool disposing) { base.Dispose(disposing); - + if (disposing) { if (Left != null) @@ -12924,32 +13495,32 @@ namespace DynamORM if (Left is Node) { Node n = (Node)Left; - + if (!n.IsDisposed) n.Dispose(disposing); } } - + if (Right != null) { if (Right is Node) { Node n = (Node)Right; - + if (!n.IsDisposed) n.Dispose(disposing); } - + Right = null; } } } } - + #endregion Binary - + #region Unary - + /// /// Represents an unary operation, as in 'x => !x'. The target must be a instance. There /// is no distinction between pre- and post- version of the same operation. @@ -12959,10 +13530,10 @@ namespace DynamORM { /// Gets the operation. public ExpressionType Operation { get; private set; } - + /// Gets host of the . public Node Target { get; private set; } - + /// /// Initializes a new instance of the class. /// @@ -12974,7 +13545,7 @@ namespace DynamORM Operation = operation; Target = target; } - + /// /// Initializes a new instance of the class. /// @@ -12985,7 +13556,7 @@ namespace DynamORM { Operation = (ExpressionType)info.GetValue("Operation", typeof(ExpressionType)); } - + /// /// Gets the object data. /// @@ -12994,20 +13565,20 @@ namespace DynamORM public override void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Operation", Operation); - + base.GetObjectData(info, context); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::Binary::Disposed}"; - + return string.Format("({0} {1})", Operation, Host.Sketch()); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -13024,10 +13595,10 @@ namespace DynamORM { if (node.IsNodeAncestor(this)) node.Host = null; - + node.Dispose(disposing); } - + Target = null; } } @@ -13035,15 +13606,15 @@ namespace DynamORM { } } - + base.Dispose(disposing); } } - + #endregion Unary - + #region Convert - + /// /// Represents a conversion operation, as in 'x => (string)x'. /// @@ -13052,10 +13623,13 @@ namespace DynamORM { /// Gets the new type to which value will be converted. public Type NewType { get; private set; } - + /// Gets host of the . - public Node Target { get { return Host; } } - + public Node Target + { + get { return Host; } + } + /// /// Initializes a new instance of the class. /// @@ -13066,7 +13640,7 @@ namespace DynamORM { NewType = newType; } - + /// /// Initializes a new instance of the class. /// @@ -13077,7 +13651,7 @@ namespace DynamORM { NewType = (Type)info.GetValue("NewType", typeof(Type)); } - + /// /// Gets the object data. /// @@ -13086,21 +13660,21 @@ namespace DynamORM public override void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("NewType", NewType); - + base.GetObjectData(info, context); } } - + #endregion Convert - + /// /// Gets the name of the member. It might be null if this instance is disposed. /// public string Name { get; internal set; } - + /// Gets host of the . public Node Host { get; internal set; } - + /// Gets reference to the parser. public DynamicParser Parser { @@ -13112,7 +13686,7 @@ namespace DynamORM _parser._allNodes.Add(this); } } - + /// /// Initializes a new instance of the class. /// @@ -13120,7 +13694,7 @@ namespace DynamORM { IsDisposed = false; } - + /// /// Initializes a new instance of the class. /// @@ -13130,10 +13704,10 @@ namespace DynamORM { if (host == null) throw new ArgumentNullException("host", "Host cannot be null."); - + Host = host; } - + /// /// Initializes a new instance of the class. /// @@ -13143,7 +13717,7 @@ namespace DynamORM { Name = name.Validated("Name"); } - + /// /// Initializes a new instance of the class. /// @@ -13155,7 +13729,7 @@ namespace DynamORM { Name = name.Validated("Name"); } - + /// /// Initializes a new instance of the class. /// @@ -13164,11 +13738,11 @@ namespace DynamORM protected Node(SerializationInfo info, StreamingContext context) { Name = info.GetString("MemberName"); - + string type = info.GetString("HostType"); Host = type == "NULL" ? null : (Node)info.GetValue("HostItem", Type.GetType(type)); } - + /// Returns whether the given node is an ancestor of this instance. /// The node to test. /// True if the given node is an ancestor of this instance. @@ -13177,31 +13751,31 @@ namespace DynamORM if (node != null) { Node parent = Host; - + while (parent != null) { if (object.ReferenceEquals(parent, node)) return true; - + parent = parent.Host; } } - + return false; } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Node::Disposed}"; - + return "{DynamicParser::Node::Empty}"; } - + #region Implementation of IDynamicMetaObjectProvider - + /// Returns the responsible /// for binding operations performed on this object. /// The expression tree representation of the runtime value. @@ -13211,26 +13785,26 @@ namespace DynamORM { if (IsDisposed) throw new ObjectDisposedException("DynamicParser.Node"); - + return new MetaNode( parameter, BindingRestrictions.GetInstanceRestriction(parameter, this), this); } - + #endregion Implementation of IDynamicMetaObjectProvider - + #region Implementation of IFinalizerDisposable - + /// Finalizes an instance of the class. ~Node() { Dispose(false); } - + /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public virtual void Dispose() @@ -13238,7 +13812,7 @@ namespace DynamORM Dispose(true); GC.SuppressFinalize(this); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. /// If set to true dispose object. @@ -13247,20 +13821,20 @@ namespace DynamORM if (disposing) { IsDisposed = true; - + if (Host != null && !Host.IsDisposed) Host.Dispose(); - + Host = null; - + Parser = null; } } - + #endregion Implementation of IFinalizerDisposable - + #region Implementation of ISerializable - + /// /// Populates a with the data needed to serialize the target object. /// @@ -13270,30 +13844,30 @@ namespace DynamORM { if (!string.IsNullOrEmpty(Name)) info.AddValue("MemberName", Name); - + info.AddValue("HostType", Host == null ? "NULL" : Host.GetType().AssemblyQualifiedName); if (Host != null) info.AddValue("HostItem", Host); } - + #endregion Implementation of ISerializable } - + #endregion Node - + #region Data - + private List _arguments = new List(); private List _allNodes = new List(); private object _uncertainResult; - + #endregion Data - + #region Properties - + /// Gets the last node (root of the tree). public Node Last { get; internal set; } - + /// /// Gets an enumeration containing the dynamic arguments used in the dynamic lambda expression parsed. /// @@ -13304,15 +13878,15 @@ namespace DynamORM List list = new List(); if (!IsDisposed && _arguments != null) list.AddRange(_arguments); - + foreach (Node.Argument arg in list) yield return arg; - + list.Clear(); list = null; } } - + /// /// Gets the number of dynamic arguments used in the dynamic lambda expression parsed. /// @@ -13320,7 +13894,7 @@ namespace DynamORM { get { return _arguments == null ? 0 : _arguments.Count; } } - + /// /// 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 class that @@ -13330,9 +13904,9 @@ namespace DynamORM { get { return _uncertainResult ?? Last; } } - + #endregion Properties - + private DynamicParser(Delegate f) { // I know this can be almost a one liner @@ -13349,7 +13923,7 @@ namespace DynamORM else throw new ArgumentException(string.Format("Argument '{0}' must be dynamic.", p.Name)); } - + try { _uncertainResult = f.DynamicInvoke(_arguments.ToArray()); @@ -13360,7 +13934,7 @@ namespace DynamORM throw; } } - + /// /// Parses the dynamic lambda expression given in the form of a delegate, and returns a new instance of the /// class that holds the dynamic arguments used in the dynamic lambda expression, and @@ -13372,83 +13946,90 @@ namespace DynamORM { return new DynamicParser(f); } - + /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { if (IsDisposed) return "{DynamicParser::Disposed}"; - + StringBuilder sb = new StringBuilder(); - + sb.Append("("); bool first = true; - + if (_arguments != null) { foreach (Node.Argument arg in _arguments) { - if (!first) sb.Append(", "); else first = false; + if (!first) sb.Append(", "); + else first = false; sb.Append(arg); } } - + sb.Append(")"); - + sb.AppendFormat(" => {0}", Result.Sketch()); - + return sb.ToString(); } - + #region Implementation of IExtendedDisposable - + /// Gets a value indicating whether this instance is disposed. public bool IsDisposed { get; private set; } - + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { IsDisposed = true; - + if (_uncertainResult != null) { if (_uncertainResult is Node) ((Node)_uncertainResult).Dispose(); - + _uncertainResult = null; } - + if (Last != null) { if (!Last.IsDisposed) Last.Dispose(); - + Last = null; } - + if (_arguments != null) { - _arguments.ForEach(x => { if (!x.IsDisposed) x.Dispose(); }); - + _arguments.ForEach(x => + { + if (!x.IsDisposed) x.Dispose(); + }); + _arguments.Clear(); _arguments = null; } - + if (_allNodes != null) { - _allNodes.ForEach(x => { if (!x.IsDisposed) x.Dispose(); }); - + _allNodes.ForEach(x => + { + if (!x.IsDisposed) x.Dispose(); + }); + _allNodes.Clear(); _allNodes = null; } } - + #endregion Implementation of IExtendedDisposable } - + /// Class that allows to use interfaces as dynamic objects. /// Type of class to proxy. /// This is temporary solution. Which allows to use builders as a dynamic type. @@ -13458,7 +14039,7 @@ namespace DynamORM private Type _type; private Dictionary _properties; private Dictionary _methods; - + /// /// Initializes a new instance of the class. /// @@ -13468,22 +14049,23 @@ namespace DynamORM { if (proxiedObject == null) throw new ArgumentNullException("proxiedObject"); - + _proxy = proxiedObject; _type = typeof(T); - + DynamicTypeMap mapper = Mapper.DynamicMapperCache.GetMapper(); - + _properties = mapper .ColumnsMap .ToDictionary( k => k.Value.Name, v => v.Value); - + _methods = GetAllMembers(_type) .Where(x => x is MethodInfo) .Cast() - .Where(m => !((m.Name.StartsWith("set_") && m.ReturnType == typeof(void)) || m.Name.StartsWith("get_"))) + .Where(m => !((m.Name.StartsWith("set_") && m.ReturnType == typeof(void)) || + m.Name.StartsWith("get_"))) .Where(m => !m.IsStatic && !m.IsGenericMethod) .ToDictionary( k => k, @@ -13491,10 +14073,12 @@ namespace DynamORM { try { - Type type = v.ReturnType == typeof(void) ? - Expression.GetActionType(v.GetParameters().Select(t => t.ParameterType).ToArray()) : - Expression.GetDelegateType(v.GetParameters().Select(t => t.ParameterType).Concat(new[] { v.ReturnType }).ToArray()); - + Type type = v.ReturnType == typeof(void) + ? Expression.GetActionType(v.GetParameters().Select(t => t.ParameterType) + .ToArray()) + : Expression.GetDelegateType(v.GetParameters().Select(t => t.ParameterType) + .Concat(new[] { v.ReturnType }).ToArray()); + return Delegate.CreateDelegate(type, _proxy, v.Name); } catch (ArgumentException) @@ -13503,7 +14087,7 @@ namespace DynamORM } }); } - + /// Provides implementation for type conversion operations. /// Classes derived from the /// class can override this method to specify dynamic behavior for @@ -13528,17 +14112,17 @@ namespace DynamORM result = _proxy; return true; } - + if (_proxy != null && binder.Type.IsAssignableFrom(_proxy.GetType())) { result = _proxy; return true; } - + return base.TryConvert(binder, out result); } - + /// Provides the implementation for operations that get member /// values. Classes derived from the /// class can override this method to specify dynamic behavior for @@ -13563,9 +14147,9 @@ namespace DynamORM try { DynamicPropertyInvoker prop = _properties.TryGetValue(binder.Name); - + result = prop.NullOr(p => p.Get.NullOr(g => g(_proxy), null), null); - + return prop != null && prop.Get != null; } catch (Exception ex) @@ -13573,7 +14157,7 @@ namespace DynamORM throw new InvalidOperationException(string.Format("Cannot get member {0}", binder.Name), ex); } } - + /// Provides the implementation for operations that set member /// values. Classes derived from the /// class can override this method to specify dynamic behavior for operations @@ -13598,21 +14182,22 @@ namespace DynamORM try { DynamicPropertyInvoker prop = _properties.TryGetValue(binder.Name); - + if (prop != null && prop.Setter != null) { prop.Set(_proxy, value); return true; } - + return false; } catch (Exception ex) { - throw new InvalidOperationException(string.Format("Cannot set member {0} to '{1}'", binder.Name, value), ex); + throw new InvalidOperationException( + string.Format("Cannot set member {0} to '{1}'", binder.Name, value), ex); } } - + /// Provides the implementation for operations that invoke a member. /// Classes derived from the /// class can override this method to specify dynamic behavior for @@ -13636,60 +14221,62 @@ namespace DynamORM /// run-time exception is thrown). public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { - return TryInvokeMethod(binder.Name, out result, args) || base.TryInvokeMember(binder, args, out result); + return TryInvokeMethod(binder.Name, out result, args) || + base.TryInvokeMember(binder, args, out result); } - + private bool TryInvokeMethod(string name, out object result, object[] args) { result = null; - + MethodInfo mi = _methods.Keys .Where(m => m.Name == name) .FirstOrDefault(m => CompareTypes(m.GetParameters().ToArray(), - args.Select(a => a.GetType()).ToArray())); - + args.Select(a => a.GetType()).ToArray())); + Delegate d = _methods.TryGetValue(mi); - + if (d != null) { result = d.DynamicInvoke(CompleteArguments(mi.GetParameters().ToArray(), args)); - + if (d.Method.ReturnType == _type && result is T) result = new DynamicProxy((T)result); - + return true; } else if (mi != null) { result = mi.Invoke(_proxy, CompleteArguments(mi.GetParameters().ToArray(), args)); - + if (mi.ReturnType == _type && result is T) result = new DynamicProxy((T)result); - + return true; } - + return false; } - + private bool CompareTypes(ParameterInfo[] parameters, Type[] types) { if (parameters.Length < types.Length || parameters.Count(p => !p.IsOptional) > types.Length) return false; - + for (int i = 0; i < types.Length; i++) - if (types[i] != parameters[i].ParameterType && !parameters[i].ParameterType.IsAssignableFrom(types[i])) + if (types[i] != parameters[i].ParameterType && + !parameters[i].ParameterType.IsAssignableFrom(types[i])) return false; - + return true; } - + private object[] CompleteArguments(ParameterInfo[] parameters, object[] arguments) { return arguments.Concat(parameters.Skip(arguments.Length).Select(p => p.DefaultValue)).ToArray(); } - + private IEnumerable GetAllMembers(Type type) { if (type.IsInterface) @@ -13697,47 +14284,47 @@ namespace DynamORM List members = new List(); List considered = new List(); Queue queue = new Queue(); - + considered.Add(type); queue.Enqueue(type); - + while (queue.Count > 0) { Type subType = queue.Dequeue(); foreach (Type subInterface in subType.GetInterfaces()) { if (considered.Contains(subInterface)) continue; - + considered.Add(subInterface); queue.Enqueue(subInterface); } - + MemberInfo[] typeProperties = subType.GetMembers( BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); - + IEnumerable newPropertyInfos = typeProperties .Where(x => !members.Contains(x)); - + members.InsertRange(0, newPropertyInfos); } - + return members; } - + return type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); } - + /// Performs application-defined tasks associated with /// freeing, releasing, or resetting unmanaged resources. public void Dispose() { object res; TryInvokeMethod("Dispose", out res, new object[] { }); - + _properties.Clear(); - + _methods = null; _properties = null; _type = null; @@ -13748,57 +14335,57 @@ namespace DynamORM } namespace Mapper - { + { /// Allows to add table name to class. [AttributeUsage(AttributeTargets.Property)] public class ColumnAttribute : Attribute { /// Gets or sets name. public string Name { get; set; } - + /// Gets or sets column type. /// Used when overriding schema. public DbType? Type { get; set; } - + /// Gets or sets a value indicating whether column is a key. public bool IsKey { get; set; } - + /// Gets or sets a value indicating whether column allows null or not. /// Information only. public bool AllowNull { get; set; } - + /// Gets or sets a value indicating whether column should have unique value. /// Used when overriding schema. public bool? IsUnique { get; set; } - + /// Gets or sets column size. /// Used when overriding schema. public int? Size { get; set; } - + /// Gets or sets column precision. /// Used when overriding schema. public byte? Precision { get; set; } - + /// Gets or sets column scale. /// Used when overriding schema. public byte? Scale { get; set; } - + /// Gets or sets a value indicating whether this column is no allowed to be inserted. /// This is only a suggestion to automated mapping. public bool IsNoInsert { get; set; } - + /// Gets or sets a value indicating whether this column is no allowed to be updated. /// This is only a suggestion to automated mapping. public bool IsNoUpdate { get; set; } - + #region Constructors - + /// Initializes a new instance of the class. public ColumnAttribute() { AllowNull = true; } - + /// Initializes a new instance of the class. /// Name of column. public ColumnAttribute(string name) @@ -13806,7 +14393,7 @@ namespace DynamORM { Name = name; } - + /// Initializes a new instance of the class. /// Set column as a key column. public ColumnAttribute(bool isKey) @@ -13814,7 +14401,7 @@ namespace DynamORM { IsKey = isKey; } - + /// Initializes a new instance of the class. /// Name of column. /// Set column as a key column. @@ -13823,7 +14410,7 @@ namespace DynamORM { IsKey = isKey; } - + /// Initializes a new instance of the class. /// Set column as a key column. /// Set column type. @@ -13832,7 +14419,7 @@ namespace DynamORM { Type = type; } - + /// Initializes a new instance of the class. /// Name of column. /// Set column as a key column. @@ -13842,7 +14429,7 @@ namespace DynamORM { Type = type; } - + /// Initializes a new instance of the class. /// Name of column. /// Set column as a key column. @@ -13853,7 +14440,7 @@ namespace DynamORM { Size = size; } - + /// Initializes a new instance of the class. /// Name of column. /// Set column as a key column. @@ -13866,7 +14453,7 @@ namespace DynamORM Precision = precision; Scale = scale; } - + /// Initializes a new instance of the class. /// Name of column. /// Set column as a key column. @@ -13879,7 +14466,7 @@ namespace DynamORM { Size = size; } - + /// Initializes a new instance of the class. /// Name of column. /// Set column as a key column. @@ -13888,15 +14475,16 @@ namespace DynamORM /// Set column value size. /// Set column value precision. /// Set column value scale. - public ColumnAttribute(string name, bool isKey, bool isUnique, DbType type, int size, byte precision, byte scale) + public ColumnAttribute(string name, bool isKey, bool isUnique, DbType type, int size, byte precision, + byte scale) : this(name, isKey, type, size, precision, scale) { IsUnique = isUnique; } - + #endregion Constructors } - + /// Type cast helper. public static class DynamicCast { @@ -13907,7 +14495,7 @@ namespace DynamORM { return type.IsValueType ? TypeDefaults.GetOrAdd(type, t => Activator.CreateInstance(t)) : null; } - + /// Casts the object to this type. /// The type to which cast value. /// The value to cast. @@ -13916,24 +14504,32 @@ namespace DynamORM { return GetConverter(type, val)(val); } - - private static readonly ConcurrentDictionary TypeDefaults = new ConcurrentDictionary(); - private static readonly ConcurrentDictionary> TypeAsCasts = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary> TypeConvert = new ConcurrentDictionary>(); + + private static readonly ConcurrentDictionary TypeDefaults = + new ConcurrentDictionary(); + + private static readonly ConcurrentDictionary> TypeAsCasts = + new ConcurrentDictionary>(); + + private static readonly ConcurrentDictionary> TypeConvert = + new ConcurrentDictionary>(); + private static readonly ParameterExpression ConvParameter = Expression.Parameter(typeof(object), "val"); - + [MethodImpl(MethodImplOptions.Synchronized)] private static Func GetConverter(Type targetType, object val) { Func fn; - + if (!targetType.IsValueType && !val.GetType().IsValueType) { if (!TypeAsCasts.TryGetValue(targetType, out fn)) { UnaryExpression instanceCast = Expression.TypeAs(ConvParameter, targetType); - - fn = Expression.Lambda>(Expression.TypeAs(instanceCast, typeof(object)), ConvParameter).Compile(); + + fn = Expression + .Lambda>(Expression.TypeAs(instanceCast, typeof(object)), + ConvParameter).Compile(); TypeAsCasts.AddOrUpdate(targetType, fn, (t, f) => fn); } } @@ -13943,51 +14539,55 @@ namespace DynamORM var key = new PairOfTypes(fromType, targetType); if (TypeConvert.TryGetValue(key, out fn)) return fn; - - fn = (Func)Expression.Lambda(Expression.Convert(Expression.Convert(Expression.Convert(ConvParameter, fromType), targetType), typeof(object)), ConvParameter).Compile(); + + fn = (Func)Expression + .Lambda( + Expression.Convert( + Expression.Convert(Expression.Convert(ConvParameter, fromType), targetType), + typeof(object)), ConvParameter).Compile(); TypeConvert.AddOrUpdate(key, fn, (t, f) => fn); } - + return fn; } - + private class PairOfTypes { private readonly Type _first; private readonly Type _second; - + public PairOfTypes(Type first, Type second) { this._first = first; this._second = second; } - + public override int GetHashCode() { return (31 * _first.GetHashCode()) + _second.GetHashCode(); } - + public override bool Equals(object obj) { if (obj == this) return true; - + var other = obj as PairOfTypes; if (other == null) return false; - + return _first.Equals(other._first) - && _second.Equals(other._second); + && _second.Equals(other._second); } } } - + /// Class with mapper cache. public static class DynamicMapperCache { private static readonly object SyncLock = new object(); private static Dictionary _cache = new Dictionary(); - + /// Get type mapper. /// Type of mapper. /// Type mapper. @@ -13995,7 +14595,7 @@ namespace DynamORM { return GetMapper(typeof(T)); } - + /// Get type mapper. /// Type of mapper. /// Type mapper. @@ -14005,24 +14605,24 @@ namespace DynamORM return null; /*if (type.IsAnonymous()) return null;*/ - + DynamicTypeMap mapper = null; - + lock (SyncLock) { if (!_cache.TryGetValue(type, out mapper)) { mapper = new DynamicTypeMap(type); - + if (mapper != null) _cache.Add(type, mapper); } } - + return mapper; } } - + /// Exception thrown when mapper fails to set or get a property. /// public class DynamicMapperException : Exception @@ -14031,13 +14631,13 @@ namespace DynamORM public DynamicMapperException() { } - + /// Initializes a new instance of the class. /// The message that describes the error. public DynamicMapperException(string message) : base(message) { } - + /// Initializes a new instance of the class. /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. @@ -14045,52 +14645,52 @@ namespace DynamORM { } } - + /// Dynamic property invoker. public class DynamicPropertyInvoker { internal class ParameterSpec { public string Name { get; set; } - + public DbType Type { get; set; } - + public int Ordinal { get; set; } } - + /// 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; } - + /// Gets value getter. public Func Get { get; private set; } - + /// Gets value setter. public Action Setter { get; private set; } - + /// Gets the property information. public PropertyInfo PropertyInfo { get; private set; } - + /// Gets name of property. public string Name { get; private set; } - + /// 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; } - + /// Gets a value indicating whether this instance hold data contract type. public bool IsDataContract { get; private set; } - + /// Initializes a new instance of the class. /// Property info to be invoked in the future. /// Column attribute if exist. @@ -14099,45 +14699,47 @@ namespace DynamORM PropertyInfo = property; Name = property.Name; Type = property.PropertyType; - + object[] ignore = property.GetCustomAttributes(typeof(IgnoreAttribute), false); - Requirements = property.GetCustomAttributes(typeof(RequiredAttribute), false).Cast().ToList(); - + Requirements = property.GetCustomAttributes(typeof(RequiredAttribute), false).Cast() + .ToList(); + Ignore = ignore != null && ignore.Length > 0; - + IsGnericEnumerable = Type.IsGenericEnumerable(); - + ArrayType = Type.IsArray ? Type.GetElementType() : IsGnericEnumerable ? Type.GetGenericArguments().First() : Type; - - IsDataContract = ArrayType.GetCustomAttributes(false).Any(x => x.GetType().Name == "DataContractAttribute"); - + + 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 (attr != null && attr.AllowNull && !Type.IsNullableType() && Type != typeof(string)) attr.AllowNull = false; - + if (property.CanRead) Get = CreateGetter(property); - + if (property.CanWrite) Setter = CreateSetter(property); } - + private Func CreateGetter(PropertyInfo property) { if (property == null || !property.CanRead) return null; - + var objParm = Expression.Parameter(typeof(object), "o"); - + return Expression.Lambda>( Expression.Convert( Expression.Property( @@ -14145,31 +14747,31 @@ namespace DynamORM property.Name), typeof(object)), objParm).Compile(); } - + private Action CreateSetter(PropertyInfo property) { if (!property.CanWrite) return null; - + var objParm = Expression.Parameter(typeof(object), "o"); var valueParm = Expression.Parameter(typeof(object), "value"); - + return Expression.Lambda>( Expression.Assign( Expression.Property( Expression.Convert(objParm, property.DeclaringType), property.Name), Expression.Convert(valueParm, property.PropertyType)), - objParm, valueParm).Compile(); + objParm, valueParm).Compile(); } - + /// Sets the specified value to destination object. /// The destination object. /// The value. public void Set(object dest, object val, bool byProperty = false) { object value = null; - + try { if (!Type.IsAssignableFrom(val.GetType())) @@ -14180,10 +14782,11 @@ namespace DynamORM { if (val is IEnumerable) { - var lst = (val as IEnumerable).Select(x => GetElementVal(ArrayType, x, byProperty)).ToList(); - + var lst = (val as IEnumerable) + .Select(x => GetElementVal(ArrayType, x, byProperty)).ToList(); + value = Array.CreateInstance(ArrayType, lst.Count); - + int i = 0; foreach (var e in lst) ((Array)value).SetValue(e, i++); @@ -14202,23 +14805,25 @@ namespace DynamORM } else value = val; - + Setter(dest, value); } catch (Exception ex) { throw new DynamicMapperException( - string.Format("Error trying to convert and set value '{0}' of type '{1}' to type '{2}' in object of type '{3}'", - val == null ? string.Empty : val.ToString(), val.GetType(), Type.FullName, dest.GetType().FullName), + string.Format( + "Error trying to convert and set value '{0}' of type '{1}' to type '{2}' in object of type '{3}'", + val == null ? string.Empty : val.ToString(), val.GetType(), Type.FullName, + dest.GetType().FullName), ex); } } - + private object GetElementVal(System.Type etype, object val, bool byProperty) { bool nullable = etype.IsGenericType && etype.GetGenericTypeDefinition() == typeof(Nullable<>); Type type = Nullable.GetUnderlyingType(etype) ?? etype; - + if (val == null && type.IsValueType) { if (nullable) @@ -14239,7 +14844,7 @@ namespace DynamORM { if (nullable) return null; - + throw; } else if (Type == typeof(string) && val.GetType() == typeof(Guid)) @@ -14255,11 +14860,12 @@ namespace DynamORM } else return (nullable) ? null : (object)Guid.Empty; } - else if (!typeof(IConvertible).IsAssignableFrom(type) && (IsDataContract || (!type.IsValueType && val is IDictionary))) + else if (!typeof(IConvertible).IsAssignableFrom(type) && + (IsDataContract || (!type.IsValueType && val is IDictionary))) { if (byProperty) return val.MapByProperty(type); - + return val.Map(type); } else @@ -14271,108 +14877,109 @@ namespace DynamORM { if (nullable) return null; - + throw; } } - + #region Type command cache - + internal ParameterSpec InsertCommandParameter { get; set; } - + internal ParameterSpec UpdateCommandParameter { get; set; } - + internal ParameterSpec DeleteCommandParameter { get; set; } - + #endregion Type command cache } - + /// Represents type columnMap. public class DynamicTypeMap { /// Gets mapper destination type creator. public Type Type { get; private set; } - + /// Gets type table description. public TableAttribute Table { get; private set; } - + /// Gets object creator. public Func Creator { get; private set; } - + /// Gets map of columns to properties. /// Key: Column name (lower), Value: . public Dictionary ColumnsMap { get; private set; } - + /// Gets map of properties to column. /// Key: Property name, Value: Column name. public Dictionary PropertyMap { get; private set; } - + /// Gets list of ignored properties. public List Ignored { get; private set; } - + /// Initializes a new instance of the class. /// Type to which columnMap objects. public DynamicTypeMap(Type type) { Type = type; - + object[] attr = type.GetCustomAttributes(typeof(TableAttribute), false); - + if (attr != null && attr.Length > 0) Table = (TableAttribute)attr[0]; - + Creator = CreateCreator(); CreateColumnAndPropertyMap(); } - + private void CreateColumnAndPropertyMap() { Dictionary columnMap = new Dictionary(); Dictionary propertyMap = new Dictionary(); List ignored = new List(); - + foreach (PropertyInfo pi in GetAllMembers(Type).Where(x => x is PropertyInfo).Cast()) { // Skip indexers if (pi.GetIndexParameters().Any()) continue; - + ColumnAttribute attr = null; - + object[] attrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true); - + if (attrs != null && attrs.Length > 0) attr = (ColumnAttribute)attrs[0]; - + string col = attr == null || string.IsNullOrEmpty(attr.Name) ? pi.Name : attr.Name; - + DynamicPropertyInvoker val = new DynamicPropertyInvoker(pi, attr); columnMap.Add(col.ToLower(), val); - + propertyMap.Add(pi.Name, col); - + if (val.Ignore) ignored.Add(pi.Name); } - + ColumnsMap = columnMap; PropertyMap = propertyMap; - + Ignored = ignored; ////columnMap.Where(i => i.Value.Ignore).Select(i => i.Value.Name).ToList(); } - + private Func CreateCreator() { var c = Type.GetConstructor(Type.EmptyTypes); if (c == null) - c = Type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null); - + c = Type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, + null); + if (c != null) return Expression.Lambda>(Expression.New(Type)).Compile(); - + return null; } - + /// Create object of type and fill values from source. /// Object containing values that will be mapped to newly created object. /// New object of type with matching values from source. @@ -14380,7 +14987,7 @@ namespace DynamORM { return Map(source, Creator()); } - + /// Create object of type and fill values from source using property names. /// Object containing values that will be mapped to newly created object. /// New object of type with matching values from source. @@ -14388,7 +14995,7 @@ namespace DynamORM { return MapByProperty(source, Creator()); } - + /// Fill values from source to object in destination. /// Object containing values that will be mapped to newly created object. /// Object of type to which copy values from source. @@ -14396,17 +15003,17 @@ namespace DynamORM public object Map(object source, object destination) { DynamicPropertyInvoker dpi = null; - + foreach (KeyValuePair item in source.ToDictionary()) { if (ColumnsMap.TryGetValue(item.Key.ToLower(), out dpi) && item.Value != null) if (dpi.Setter != null) dpi.Set(destination, item.Value); } - + return destination; } - + /// Fill values from source to object in destination using property names. /// Object containing values that will be mapped to newly created object. /// Object of type to which copy values from source. @@ -14415,7 +15022,7 @@ namespace DynamORM { string cn = null; DynamicPropertyInvoker dpi = null; - + foreach (KeyValuePair item in source.ToDictionary()) { if (PropertyMap.TryGetValue(item.Key, out cn) && item.Value != null) @@ -14423,46 +15030,46 @@ namespace DynamORM if (dpi.Setter != null) dpi.Set(destination, item.Value, true); } - + 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.Where(x => !x.ElementRequirement)) { var valid = r.ValidateSimpleValue(prop, v); - + if (valid == ValidateResult.Valid) { if (prop.Type.IsArray || prop.IsGnericEnumerable) { var map = DynamicMapperCache.GetMapper(prop.ArrayType); - + var list = v as IEnumerable; - + if (list == null) { var enumerable = v as IEnumerable; if (enumerable != null) list = enumerable.Cast(); } - + if (list != null) foreach (var item in list) { @@ -14470,8 +15077,9 @@ namespace DynamORM { foreach (var re in prop.Requirements.Where(x => x.ElementRequirement)) { - var validelem = re.ValidateSimpleValue(prop.ArrayType, prop.ArrayType.IsGenericEnumerable(), item); - + var validelem = re.ValidateSimpleValue(prop.ArrayType, + prop.ArrayType.IsGenericEnumerable(), item); + if (validelem == ValidateResult.NotSupported) { result.AddRange(map.ValidateObject(item)); @@ -14491,16 +15099,16 @@ namespace DynamORM 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, @@ -14510,10 +15118,10 @@ namespace DynamORM }); } } - + return result; } - + private IEnumerable GetAllMembers(Type type) { if (type.IsInterface) @@ -14521,66 +15129,66 @@ namespace DynamORM List members = new List(); List considered = new List(); Queue queue = new Queue(); - + considered.Add(type); queue.Enqueue(type); - + while (queue.Count > 0) { Type subType = queue.Dequeue(); foreach (Type subInterface in subType.GetInterfaces()) { if (considered.Contains(subInterface)) continue; - + considered.Add(subInterface); queue.Enqueue(subInterface); } - + MemberInfo[] typeProperties = subType.GetMembers( BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); - + IEnumerable newPropertyInfos = typeProperties .Where(x => !members.Contains(x)); - + members.InsertRange(0, newPropertyInfos); } - + return members; } - + return type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); } - + #region Type command cache - + internal string InsertCommandText { get; set; } - + internal string UpdateCommandText { get; set; } - + internal string DeleteCommandText { get; set; } - + #endregion Type command cache } - + /// Allows to add ignore action to property. /// Property still get's mapped from output. [AttributeUsage(AttributeTargets.Property)] public class IgnoreAttribute : Attribute { } - + /// Allows to add table name to class. [AttributeUsage(AttributeTargets.Class)] public class TableAttribute : Attribute { /// Gets or sets table owner name. public string Owner { get; set; } - + /// Gets or sets name. public string Name { get; set; } - + /// Gets or sets a value indicating whether override database /// schema values. /// If database doesn't support schema, you still have to @@ -14590,31 +15198,34 @@ namespace DynamORM } namespace Objects - { + { /// Base class for strong typed objects. public class DynamicEntityBase { private Dictionary _changedFields = new Dictionary(); private DynamicEntityState _dynamicEntityState = DynamicEntityState.Unknown; - + /// Occurs when object property is changing. public event EventHandler PropertyChanging; - + /// Gets the state of the dynamic entity. /// Current state of entity. - public virtual DynamicEntityState GetDynamicEntityState() { return _dynamicEntityState; } - + public virtual DynamicEntityState GetDynamicEntityState() + { + return _dynamicEntityState; + } + /// Sets the state of the dynamic entity. /// Using this method will reset modified fields list. /// The state. public virtual void SetDynamicEntityState(DynamicEntityState state) { _dynamicEntityState = state; - + if (_changedFields != null) _changedFields.Clear(); } - + /// Called when object property is changing. /// Name of the property. /// The old property value. @@ -14623,7 +15234,7 @@ namespace DynamORM { OnPropertyChanging(new DynamicPropertyChangingEventArgs(propertyName, oldValue, newValue)); } - + /// Raises the event. /// The instance containing the event data. protected virtual void OnPropertyChanging(DynamicPropertyChangingEventArgs e) @@ -14632,14 +15243,14 @@ namespace DynamORM if (PropertyChanging != null) PropertyChanging(this, e); } - + /// Validates this object instance. /// Returns list of containing results of validation. public virtual IList Validate() { return DynamicMapperCache.GetMapper(this.GetType()).ValidateObject(this); } - + /// Saves this object to database. /// The database. /// Returns true if operation was successful. @@ -14650,37 +15261,38 @@ namespace DynamORM { default: case DynamicEntityState.Unknown: - throw new InvalidOperationException("Unknown object state. Unable to decide whish action should be performed."); - + throw new InvalidOperationException( + "Unknown object state. Unable to decide whish action should be performed."); + case DynamicEntityState.New: return Insert(database); - + case DynamicEntityState.Existing: if (IsModified()) return Update(database); - + return true; - + case DynamicEntityState.ToBeDeleted: return Delete(database); - + case DynamicEntityState.Deleted: throw new InvalidOperationException("Unable to do any database action on deleted object."); } } - + /// Determines whether this instance is in existing state and fields was modified since this state was set modified. /// Returns true if this instance is modified; otherwise, false. public virtual bool IsModified() { if (GetDynamicEntityState() != DynamicEntityState.Existing) return false; - + return _changedFields != null && _changedFields.Any(); } - + #region Insert/Update/Delete - + /// Inserts this object to database. /// The database. /// Returns true if operation was successful. @@ -14689,18 +15301,18 @@ namespace DynamORM using (var query = db.Insert(this.GetType())) { if (query - .Values(x => this) - .Execute() > 0) + .Values(x => this) + .Execute() > 0) { _changedFields.Clear(); SetDynamicEntityState(DynamicEntityState.Existing); return true; } } - + return false; } - + /// Updates this object in database. /// The database. /// Returns true if operation was successful. @@ -14711,9 +15323,9 @@ namespace DynamORM using (var query = db.Update(t)) { MakeQueryWhere(mapper, query); - + bool any = false; - + if (_changedFields.Any()) { foreach (var cf in _changedFields) @@ -14722,56 +15334,56 @@ namespace DynamORM var pm = mapper.ColumnsMap[cn.ToLower()]; if (pm.Ignore) continue; - + if (pm.Column != null) { if (pm.Column.IsKey || pm.Column.IsNoUpdate) continue; - + if (!pm.Column.AllowNull && cf.Value == null) continue; } - + query.Values(cn, cf.Value); any = true; } } - + if (!any) foreach (var pmk in mapper.ColumnsMap) { var pm = pmk.Value; var val = pm.Get(this); var cn = pm.Name; - + if (pm.Ignore) continue; - + if (pm.Column != null) { if (!string.IsNullOrEmpty(pm.Column.Name)) cn = pm.Column.Name; - + if (pm.Column.IsKey) continue; - + if (!pm.Column.AllowNull && val == null) continue; } - + query.Values(cn, val); } - + if (query.Execute() == 0) return false; - + SetDynamicEntityState(DynamicEntityState.Existing); _changedFields.Clear(); - + return true; } } - + /// Deletes this object from database. /// The database. /// Returns true if operation was successful. @@ -14779,24 +15391,24 @@ namespace DynamORM { var t = this.GetType(); var mapper = DynamicMapperCache.GetMapper(t); - + using (var query = db.Delete(t)) { MakeQueryWhere(mapper, query); - + if (query.Execute() == 0) return false; - + SetDynamicEntityState(DynamicEntityState.Deleted); } - + return true; } - + #endregion Insert/Update/Delete - + #region Select - + /// Refresh non key data from database. /// The database. /// All properties that are primary key values must be filled. @@ -14809,27 +15421,27 @@ namespace DynamORM { MakeQueryWhere(mapper, query); var o = (query.Execute() as IEnumerable).FirstOrDefault(); - + if (o == null) return false; - + mapper.Map(o, this); - + SetDynamicEntityState(DynamicEntityState.Existing); _changedFields.Clear(); } - + return true; } - + #endregion Select - + #region Query Helpers - + private void MakeQueryWhere(DynamicTypeMap mapper, IDynamicUpdateQueryBuilder query) { bool keyNotDefined = true; - + foreach (var cm in mapper.ColumnsMap) { if (cm.Value.Column != null && cm.Value.Column.IsKey) @@ -14838,16 +15450,16 @@ namespace DynamORM keyNotDefined = false; } } - + if (keyNotDefined) throw new InvalidOperationException(String.Format("Class '{0}' have no key columns defined", this.GetType().FullName)); } - + private void MakeQueryWhere(DynamicTypeMap mapper, IDynamicDeleteQueryBuilder query) { bool keyNotDefined = true; - + foreach (var cm in mapper.ColumnsMap) { if (cm.Value.Column != null && cm.Value.Column.IsKey) @@ -14856,39 +15468,40 @@ namespace DynamORM keyNotDefined = false; } } - + if (keyNotDefined) throw new InvalidOperationException(String.Format("Class '{0}' have no key columns defined", this.GetType().FullName)); } - + private void MakeQueryWhere(DynamicTypeMap mapper, IDynamicSelectQueryBuilder query) { bool keyNotDefined = true; - + foreach (var cm in mapper.ColumnsMap) { if (cm.Value.Column != null && cm.Value.Column.IsKey) { var v = cm.Value.Get(this); - + if (v == null) - throw new InvalidOperationException(String.Format("Class '{0}' have key columns {1} not filled with data.", + throw new InvalidOperationException(String.Format( + "Class '{0}' have key columns {1} not filled with data.", this.GetType().FullName, cm.Value.Name)); - + query.Where(cm.Key, DynamicColumn.CompareOperator.Eq, cm.Value.Get(this)); keyNotDefined = false; } } - + if (keyNotDefined) throw new InvalidOperationException(String.Format("Class '{0}' have no key columns defined", this.GetType().FullName)); } - + #endregion Query Helpers } - + /// Possible states of dynamic database objects. public enum DynamicEntityState { @@ -14896,20 +15509,20 @@ namespace DynamORM /// In this state repository will be unable to tell if object with this state should be added /// or updated in database, but you can still manually perform update or insert on such object. Unknown, - + /// This state should be set to new objects in database. New, - + /// This state is ser when data is refreshed from database or object was loaded from repository. Existing, - + /// You can set this state to an object if you want repository to perform delete from database. ToBeDeleted, - + /// This state is set for objects that were deleted from database. Deleted, } - + /// Class containing changed property data. /// public class DynamicPropertyChangingEventArgs : EventArgs @@ -14917,15 +15530,15 @@ namespace DynamORM /// Gets the name of the property. /// The name of the property. public string PropertyName { get; private set; } - + /// Gets the old property value. /// The old value. public object OldValue { get; private set; } - + /// Gets the new property value. /// The new value. public object NewValue { get; private set; } - + /// Initializes a new instance of the class. /// Name of the property. /// The old property value. @@ -14937,20 +15550,20 @@ namespace DynamORM NewValue = newValue; } } - + /// Base repository class for specified object type. /// Type of stored object. public class DynamicRepositoryBase : IDisposable where T : DynamicEntityBase { private DynamicDatabase _database; - + /// Initializes a new instance of the class. /// The database. public DynamicRepositoryBase(DynamicDatabase database) { _database = database; } - + /// Get all rows from database. /// Objects enumerator. public virtual IEnumerable GetAll() @@ -14958,7 +15571,7 @@ namespace DynamORM using (var q = _database.From()) return EnumerateQuery(q); } - + /// Get rows from database by custom query. /// The query. /// Query must be based on object type. @@ -14967,27 +15580,29 @@ namespace DynamORM { return EnumerateQuery(query); } - + private IEnumerable EnumerateQuery(IDynamicSelectQueryBuilder query, bool forceType = true) { if (forceType) { var mapper = DynamicMapperCache.GetMapper(typeof(T)); - - var tn = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? - mapper.Type.Name : mapper.Table.Name; - + + var tn = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) + ? mapper.Type.Name + : mapper.Table.Name; + if (!query.Tables.Any(t => t.Name == tn)) - throw new InvalidOperationException(string.Format("Query is not related to '{0}' class.", typeof(T).FullName)); + throw new InvalidOperationException(string.Format("Query is not related to '{0}' class.", + typeof(T).FullName)); } - + foreach (var o in query.Execute()) { o.SetDynamicEntityState(DynamicEntityState.Existing); yield return o; } } - + /// Saves single object to database. /// The element. /// Returns true if operation was successful. @@ -14995,7 +15610,7 @@ namespace DynamORM { return element.Save(_database); } - + /// Saves collection of objects to database. /// The element. /// Returns true if operation was successful. @@ -15003,7 +15618,7 @@ namespace DynamORM { return element.All(x => x.Save(_database)); } - + /// Insert single object to database. /// The element. /// Returns true if operation was successful. @@ -15011,7 +15626,7 @@ namespace DynamORM { return element.Insert(_database); } - + /// Insert collection of objects to database. /// The element. /// Returns true if operation was successful. @@ -15019,7 +15634,7 @@ namespace DynamORM { return element.All(x => x.Insert(_database)); } - + /// Update single object to database. /// The element. /// Returns true if operation was successful. @@ -15027,7 +15642,7 @@ namespace DynamORM { return element.Update(_database); } - + /// Update collection of objects to database. /// The element. /// Returns true if operation was successful. @@ -15035,7 +15650,7 @@ namespace DynamORM { return element.All(x => x.Update(_database)); } - + /// Delete single object to database. /// The element. /// Returns true if operation was successful. @@ -15043,7 +15658,7 @@ namespace DynamORM { return element.Delete(_database); } - + /// Delete collection of objects to database. /// The element. /// Returns true if operation was successful. @@ -15051,7 +15666,7 @@ namespace DynamORM { return element.All(x => x.Delete(_database)); } - + /// Releases unmanaged and - optionally - managed resources. public virtual void Dispose() { @@ -15061,33 +15676,33 @@ namespace DynamORM } namespace Validation - { + { /// Required attribute can be used to validate fields in objects using mapper class. [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 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; } - + /// Gets or sets a value indicating whether this is an element requirement. public bool ElementRequirement { 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). @@ -15100,7 +15715,7 @@ namespace DynamORM Min = (decimal)val; Required = required; } - + /// Initializes a new instance of the class. /// Minimum value to set. /// Maximum value to set. @@ -15111,7 +15726,7 @@ namespace DynamORM Max = (decimal)max; Required = required; } - + /// Initializes a new instance of the class. /// Minimum value to set. /// Maximum value to set. @@ -15124,12 +15739,12 @@ namespace DynamORM Pattern = new Regex(pattern, RegexOptions.Compiled); Required = required; } - + internal ValidateResult ValidateSimpleValue(DynamicPropertyInvoker dpi, object val) { return ValidateSimpleValue(dpi.Type, dpi.IsGnericEnumerable, val); } - + internal ValidateResult ValidateSimpleValue(Type type, bool isGnericEnumerable, object val) { if (val == null) @@ -15139,42 +15754,44 @@ namespace DynamORM else return ValidateResult.Valid; } - + if (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?) + 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 (type.IsArray || isGnericEnumerable) { int? cnt = null; - + var list = val as IEnumerable; if (list != null) cnt = list.Count(); @@ -15184,84 +15801,83 @@ namespace DynamORM if (enumerable != null) cnt = enumerable.Cast().Count(); } - + if (Min.HasValue && Min.Value > cnt) return ValidateResult.TooFewElementsInCollection; - + if (Max.HasValue && Max.Value < cnt) return ValidateResult.TooManyElementsInCollection; - + return ValidateResult.Valid; } else if (type == typeof(string)) { var str = (string)val; - + 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; } - + 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; } - + /// Gets the result. - public ValidateResult Result { get;internal set;} + public ValidateResult Result { get; internal set; } } } -} - +} \ No newline at end of file diff --git a/DynamORM.Tests/DynamORM.Tests.csproj b/DynamORM.Tests/DynamORM.Tests.csproj index 251b8aa..fd25143 100644 --- a/DynamORM.Tests/DynamORM.Tests.csproj +++ b/DynamORM.Tests/DynamORM.Tests.csproj @@ -3,7 +3,7 @@ net8.0 Dynamic Object-Relational Mapping tests library. - Copyright © RUSSEK Software 2012-2024 + Copyright © RUSSEK Software 2012-2026 RUSSEK Software Grzegorz Russek 1.8 diff --git a/DynamORM.Tests/Helpers/AttachToDebugger.cs b/DynamORM.Tests/Helpers/AttachToDebugger.cs index 16bb134..f4e0702 100644 --- a/DynamORM.Tests/Helpers/AttachToDebugger.cs +++ b/DynamORM.Tests/Helpers/AttachToDebugger.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Helpers/Dynamic/DynamicParserTests.cs b/DynamORM.Tests/Helpers/Dynamic/DynamicParserTests.cs index 8a2f232..25961b9 100644 --- a/DynamORM.Tests/Helpers/Dynamic/DynamicParserTests.cs +++ b/DynamORM.Tests/Helpers/Dynamic/DynamicParserTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Helpers/PoolingTests.cs b/DynamORM.Tests/Helpers/PoolingTests.cs index dc34e53..55bb032 100644 --- a/DynamORM.Tests/Helpers/PoolingTests.cs +++ b/DynamORM.Tests/Helpers/PoolingTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Helpers/Users.cs b/DynamORM.Tests/Helpers/Users.cs index f7b4e4d..e402075 100644 --- a/DynamORM.Tests/Helpers/Users.cs +++ b/DynamORM.Tests/Helpers/Users.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Helpers/UsersBareBoneClass.cs b/DynamORM.Tests/Helpers/UsersBareBoneClass.cs index 3b72195..5e1178f 100644 --- a/DynamORM.Tests/Helpers/UsersBareBoneClass.cs +++ b/DynamORM.Tests/Helpers/UsersBareBoneClass.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Helpers/Validation/ObjectValidationTest.cs b/DynamORM.Tests/Helpers/Validation/ObjectValidationTest.cs index 103d4ab..d9cd99b 100644 --- a/DynamORM.Tests/Helpers/Validation/ObjectValidationTest.cs +++ b/DynamORM.Tests/Helpers/Validation/ObjectValidationTest.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Modify/DynamicModificationTests.cs b/DynamORM.Tests/Modify/DynamicModificationTests.cs index 378f58e..a1e6746 100644 --- a/DynamORM.Tests/Modify/DynamicModificationTests.cs +++ b/DynamORM.Tests/Modify/DynamicModificationTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Modify/DynamicNoSchemaModificationTests.cs b/DynamORM.Tests/Modify/DynamicNoSchemaModificationTests.cs index 5943acc..a57ac92 100644 --- a/DynamORM.Tests/Modify/DynamicNoSchemaModificationTests.cs +++ b/DynamORM.Tests/Modify/DynamicNoSchemaModificationTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs b/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs index 546e355..a8fd296 100644 --- a/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs +++ b/DynamORM.Tests/Modify/DynamicTypeSchemaModificationTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Modify/ParserTests.cs b/DynamORM.Tests/Modify/ParserTests.cs index 1e98178..99154e7 100644 --- a/DynamORM.Tests/Modify/ParserTests.cs +++ b/DynamORM.Tests/Modify/ParserTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/DynamicAccessTests.cs b/DynamORM.Tests/Select/DynamicAccessTests.cs index 4105b4c..3664750 100644 --- a/DynamORM.Tests/Select/DynamicAccessTests.cs +++ b/DynamORM.Tests/Select/DynamicAccessTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/DynamicNoSchemaAccessTests.cs b/DynamORM.Tests/Select/DynamicNoSchemaAccessTests.cs index 267c776..51aafcc 100644 --- a/DynamORM.Tests/Select/DynamicNoSchemaAccessTests.cs +++ b/DynamORM.Tests/Select/DynamicNoSchemaAccessTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/DynamicTypeSchemaAccessTests.cs b/DynamORM.Tests/Select/DynamicTypeSchemaAccessTests.cs index 998c262..67ce7c5 100644 --- a/DynamORM.Tests/Select/DynamicTypeSchemaAccessTests.cs +++ b/DynamORM.Tests/Select/DynamicTypeSchemaAccessTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/LegacyParserTests.cs b/DynamORM.Tests/Select/LegacyParserTests.cs index 8053aa7..3f0069f 100644 --- a/DynamORM.Tests/Select/LegacyParserTests.cs +++ b/DynamORM.Tests/Select/LegacyParserTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/ParserTests.cs b/DynamORM.Tests/Select/ParserTests.cs index a8c0f1e..260eb8c 100644 --- a/DynamORM.Tests/Select/ParserTests.cs +++ b/DynamORM.Tests/Select/ParserTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/RenamedTypedAccessTests.cs b/DynamORM.Tests/Select/RenamedTypedAccessTests.cs index a90b7b8..4cb7a33 100644 --- a/DynamORM.Tests/Select/RenamedTypedAccessTests.cs +++ b/DynamORM.Tests/Select/RenamedTypedAccessTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/Select/TypedAccessTests.cs b/DynamORM.Tests/Select/TypedAccessTests.cs index e1d2bc0..99a0be5 100644 --- a/DynamORM.Tests/Select/TypedAccessTests.cs +++ b/DynamORM.Tests/Select/TypedAccessTests.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM.Tests/TestsBase.cs b/DynamORM.Tests/TestsBase.cs index d5a0551..93454f4 100644 --- a/DynamORM.Tests/TestsBase.cs +++ b/DynamORM.Tests/TestsBase.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/Extensions/DynamicHavingQueryExtensions.cs b/DynamORM/Builders/Extensions/DynamicHavingQueryExtensions.cs index 3193bd5..8377bba 100644 --- a/DynamORM/Builders/Extensions/DynamicHavingQueryExtensions.cs +++ b/DynamORM/Builders/Extensions/DynamicHavingQueryExtensions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/Builders/Extensions/DynamicModifyBuilderExtensions.cs b/DynamORM/Builders/Extensions/DynamicModifyBuilderExtensions.cs index 4e99d7c..8f24c4a 100644 --- a/DynamORM/Builders/Extensions/DynamicModifyBuilderExtensions.cs +++ b/DynamORM/Builders/Extensions/DynamicModifyBuilderExtensions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/Builders/Extensions/DynamicWhereQueryExtensions.cs b/DynamORM/Builders/Extensions/DynamicWhereQueryExtensions.cs index 96e76f9..2b60a69 100644 --- a/DynamORM/Builders/Extensions/DynamicWhereQueryExtensions.cs +++ b/DynamORM/Builders/Extensions/DynamicWhereQueryExtensions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs b/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs index 915e2cb..6ef0ede 100644 --- a/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs +++ b/DynamORM/Builders/IDynamicDeleteQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/IDynamicInsertQueryBuilder.cs b/DynamORM/Builders/IDynamicInsertQueryBuilder.cs index 866f9e7..f02ff48 100644 --- a/DynamORM/Builders/IDynamicInsertQueryBuilder.cs +++ b/DynamORM/Builders/IDynamicInsertQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/IDynamicQueryBuilder.cs b/DynamORM/Builders/IDynamicQueryBuilder.cs index 4366bb3..b05e911 100644 --- a/DynamORM/Builders/IDynamicQueryBuilder.cs +++ b/DynamORM/Builders/IDynamicQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/IDynamicSelectQueryBuilder.cs b/DynamORM/Builders/IDynamicSelectQueryBuilder.cs index 4ca0448..e9c0e72 100644 --- a/DynamORM/Builders/IDynamicSelectQueryBuilder.cs +++ b/DynamORM/Builders/IDynamicSelectQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs b/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs index 5938a47..b9908be 100644 --- a/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs +++ b/DynamORM/Builders/IDynamicUpdateQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/IParameter.cs b/DynamORM/Builders/IParameter.cs index 999e3f9..c5838e6 100644 --- a/DynamORM/Builders/IParameter.cs +++ b/DynamORM/Builders/IParameter.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/ITableInfo.cs b/DynamORM/Builders/ITableInfo.cs index b32513b..44c7d46 100644 --- a/DynamORM/Builders/ITableInfo.cs +++ b/DynamORM/Builders/ITableInfo.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/Implementation/DynamicDeleteQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicDeleteQueryBuilder.cs index 25ebdc0..7486cd2 100644 --- a/DynamORM/Builders/Implementation/DynamicDeleteQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicDeleteQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/Builders/Implementation/DynamicInsertQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicInsertQueryBuilder.cs index 8926af5..35d78bf 100644 --- a/DynamORM/Builders/Implementation/DynamicInsertQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicInsertQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/Builders/Implementation/DynamicModifyBuilder.cs b/DynamORM/Builders/Implementation/DynamicModifyBuilder.cs index 2bf7a38..baeefe1 100644 --- a/DynamORM/Builders/Implementation/DynamicModifyBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicModifyBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs index f38c1ed..7b9ebda 100644 --- a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs index da5add2..5bc86d3 100644 --- a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution @@ -139,36 +139,35 @@ namespace DynamORM.Builders.Implementation /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() { - DynamicCachedReader cache = null; using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.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 + .SetCommand(this) + .ExecuteReader()) + using (IDataReader cache = new DynamicCachedReader(rdr)) + while (cache.Read()) { - val = cache.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); + dynamic val = null; - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } + // 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 = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); - yield return val; - } + throw new ArgumentException( + string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return val; + } } } @@ -177,7 +176,6 @@ namespace DynamORM.Builders.Implementation /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() where T : class { - DynamicCachedReader cache = null; DynamicTypeMap mapper = DynamicMapperCache.GetMapper(); if (mapper == null) @@ -187,31 +185,31 @@ namespace DynamORM.Builders.Implementation using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.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 + .SetCommand(this) + .ExecuteReader()) + using (IDataReader cache = new DynamicCachedReader(rdr)) + while (cache.Read()) { - val = cache.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); + dynamic val = null; - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } + // 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 = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); - yield return mapper.Create(val) as T; - } + throw new ArgumentException( + string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return mapper.Create(val) as T; + } } } @@ -232,16 +230,13 @@ namespace DynamORM.Builders.Implementation /// Action containing reader. public virtual void ExecuteCachedDataReader(Action reader) { - DynamicCachedReader cache = null; - using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - reader(cache); + using (IDataReader cache = new DynamicCachedReader(rdr)) + reader(cache); } /// Returns a single result. diff --git a/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs index 074b3ff..030382c 100644 --- a/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicUpdateQueryBuilder.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Some of methods in this code file is based on Kerosene ORM solution diff --git a/DynamORM/DynamORM.csproj b/DynamORM/DynamORM.csproj index 69389d8..3c93529 100644 --- a/DynamORM/DynamORM.csproj +++ b/DynamORM/DynamORM.csproj @@ -3,7 +3,7 @@ netstandard2.0;net472;net6.0;net8.0;net10.0 Dynamic Object-Relational Mapping library. - Copyright © RUSSEK Software 2012-2024 + Copyright © RUSSEK Software 2012-2026 RUSSEK Software Grzegorz Russek 1.9 diff --git a/DynamORM/DynamicColumn.cs b/DynamORM/DynamicColumn.cs index 960646a..c7f45db 100644 --- a/DynamORM/DynamicColumn.cs +++ b/DynamORM/DynamicColumn.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicCommand.cs b/DynamORM/DynamicCommand.cs index e71b8a7..6ae0c68 100644 --- a/DynamORM/DynamicCommand.cs +++ b/DynamORM/DynamicCommand.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicConnection.cs b/DynamORM/DynamicConnection.cs index 45cac06..346083a 100644 --- a/DynamORM/DynamicConnection.cs +++ b/DynamORM/DynamicConnection.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs index 808dd1f..c54be39 100644 --- a/DynamORM/DynamicDatabase.cs +++ b/DynamORM/DynamicDatabase.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1327,7 +1327,6 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(string sql, params object[] args) { - DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) { @@ -1335,28 +1334,30 @@ namespace DynamORM .SetCommand(sql) .AddParameters(this, args) .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.Read()) + using (IDataReader cache = new DynamicCachedReader(rdr)) { - dynamic val = null; - - // Work around to avoid yield being in try...catch block: - // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch - try + while (cache.Read()) { - val = cache.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); + dynamic val = null; - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } + // Work around to avoid yield being in try...catch block: + // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch + try + { + val = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); - yield return val; + throw new ArgumentException( + string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return val; + } } } } @@ -1366,36 +1367,35 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(IDynamicQueryBuilder builder) { - DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) { using (IDataReader rdr = cmd .SetCommand(builder) .ExecuteReader()) - cache = new DynamicCachedReader(rdr); - - while (cache.Read()) - { - dynamic val = null; - - // Work around to avoid yield being in try...catch block: - // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch - try + using (var cache = new DynamicCachedReader(rdr)) + while (cache.Read()) { - val = cache.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); + dynamic val = null; - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } + // Work around to avoid yield being in try...catch block: + // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch + try + { + val = cache.RowToDynamic(); + } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); - yield return val; - } + throw new ArgumentException( + string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return val; + } } } diff --git a/DynamORM/DynamicDatabaseOptions.cs b/DynamORM/DynamicDatabaseOptions.cs index 97de33d..a561167 100644 --- a/DynamORM/DynamicDatabaseOptions.cs +++ b/DynamORM/DynamicDatabaseOptions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicExpando.cs b/DynamORM/DynamicExpando.cs index bc110fc..3a79196 100644 --- a/DynamORM/DynamicExpando.cs +++ b/DynamORM/DynamicExpando.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicExtensions.cs b/DynamORM/DynamicExtensions.cs index d90e1ed..f028d95 100644 --- a/DynamORM/DynamicExtensions.cs +++ b/DynamORM/DynamicExtensions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicProcedureInvoker.cs b/DynamORM/DynamicProcedureInvoker.cs index 699d6f7..1f71167 100644 --- a/DynamORM/DynamicProcedureInvoker.cs +++ b/DynamORM/DynamicProcedureInvoker.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -282,18 +282,17 @@ namespace DynamORM else if (types[0] == typeof(DataTable)) { using (IDataReader rdr = cmd.ExecuteReader()) - mainResult = rdr.CachedReader().ToDataTable(binder.Name); + using (IDataReader cache = rdr.CachedReader()) + mainResult = cache.ToDataTable(binder.Name); } else if (types[0].IsGenericEnumerable()) { Type argType = types[0].GetGenericArguments().First(); if (argType == typeof(object)) { - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); - - mainResult = cache.EnumerateReader().ToList(); + using (IDataReader cache = rdr.CachedReader()) + mainResult = cache.EnumerateReader().ToList(); } else if (argType.IsValueType || argType == typeof(string)) { @@ -302,12 +301,10 @@ namespace DynamORM object defVal = listType.GetDefaultValue(); - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); - - while (cache.Read()) - listInstance.Add(cache[0] != null && cache[0] != DBNull.Value ? argType.CastObject(cache[0]) : defVal); + using (IDataReader cache = rdr.CachedReader()) + while (cache.Read()) + listInstance.Add(cache[0] != null && cache[0] != DBNull.Value ? argType.CastObject(cache[0]) : defVal); mainResult = listInstance; } @@ -318,15 +315,13 @@ namespace DynamORM object defVal = listType.GetDefaultValue(); - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); - - while (cache.Read()) - { - if (cache[0] != null && cache[0] != DBNull.Value && Guid.TryParse(cache[0].ToString(), out Guid g)) - listInstance.Add(g); - } + using (IDataReader cache = rdr.CachedReader()) + while (cache.Read()) + { + if (cache[0] != null && cache[0] != DBNull.Value && Guid.TryParse(cache[0].ToString(), out Guid g)) + listInstance.Add(g); + } mainResult = listInstance; } @@ -336,18 +331,18 @@ namespace DynamORM if (mapper == null) throw new InvalidCastException(string.Format("Don't know what to do with this type: '{0}'.", argType.ToString())); - IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - cache = rdr.CachedReader(); + using (IDataReader cache = rdr.CachedReader()) + { + var lt = typeof(List<>); + var ltc = lt.MakeGenericType(argType); + var instance = Activator.CreateInstance(ltc) as IList; - var lt = typeof(List<>); - var ltc = lt.MakeGenericType(argType); - var instance = Activator.CreateInstance(ltc) as IList; + foreach (var item in cache.EnumerateReader()) + instance.Add(DynamicExtensions.Map(item, argType)); - foreach (var item in cache.EnumerateReader()) - instance.Add(DynamicExtensions.Map(item, argType)); - - mainResult = instance; + mainResult = instance; + } //mainResult = cache.EnumerateReader().MapEnumerable(argType).ToList(); } diff --git a/DynamORM/DynamicQueryException.cs b/DynamORM/DynamicQueryException.cs index e4c1a2d..d6a1756 100644 --- a/DynamORM/DynamicQueryException.cs +++ b/DynamORM/DynamicQueryException.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicSchemaColumn.cs b/DynamORM/DynamicSchemaColumn.cs index 72364f2..84e123c 100644 --- a/DynamORM/DynamicSchemaColumn.cs +++ b/DynamORM/DynamicSchemaColumn.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicTable.cs b/DynamORM/DynamicTable.cs index e333dd5..ab28af1 100644 --- a/DynamORM/DynamicTable.cs +++ b/DynamORM/DynamicTable.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/DynamicTransaction.cs b/DynamORM/DynamicTransaction.cs index 28df70a..ea0747b 100644 --- a/DynamORM/DynamicTransaction.cs +++ b/DynamORM/DynamicTransaction.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/CollectionComparer.cs b/DynamORM/Helpers/CollectionComparer.cs index 1c82fca..067d010 100644 --- a/DynamORM/Helpers/CollectionComparer.cs +++ b/DynamORM/Helpers/CollectionComparer.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/Dynamics/DynamicParser.cs b/DynamORM/Helpers/Dynamics/DynamicParser.cs index c045a56..972bcd6 100644 --- a/DynamORM/Helpers/Dynamics/DynamicParser.cs +++ b/DynamORM/Helpers/Dynamics/DynamicParser.cs @@ -1,6 +1,6 @@ -/* +/* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * This code file is based on Kerosene ORM solution for parsing dynamic diff --git a/DynamORM/Helpers/Dynamics/DynamicProxy.cs b/DynamORM/Helpers/Dynamics/DynamicProxy.cs index deaaf66..f00b57a 100644 --- a/DynamORM/Helpers/Dynamics/DynamicProxy.cs +++ b/DynamORM/Helpers/Dynamics/DynamicProxy.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/FrameworkTools.cs b/DynamORM/Helpers/FrameworkTools.cs index 58fdf77..5275d37 100644 --- a/DynamORM/Helpers/FrameworkTools.cs +++ b/DynamORM/Helpers/FrameworkTools.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/IExtendedDisposable.cs b/DynamORM/Helpers/IExtendedDisposable.cs index 8b0f802..5a9b6cf 100644 --- a/DynamORM/Helpers/IExtendedDisposable.cs +++ b/DynamORM/Helpers/IExtendedDisposable.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/IFinalizerDisposable.cs b/DynamORM/Helpers/IFinalizerDisposable.cs index d53c6d4..a694ee0 100644 --- a/DynamORM/Helpers/IFinalizerDisposable.cs +++ b/DynamORM/Helpers/IFinalizerDisposable.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/StringExtensions.cs b/DynamORM/Helpers/StringExtensions.cs index a942b1c..32c2957 100644 --- a/DynamORM/Helpers/StringExtensions.cs +++ b/DynamORM/Helpers/StringExtensions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Helpers/UnclassifiedExtensions.cs b/DynamORM/Helpers/UnclassifiedExtensions.cs index b2d0335..59c2ed3 100644 --- a/DynamORM/Helpers/UnclassifiedExtensions.cs +++ b/DynamORM/Helpers/UnclassifiedExtensions.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/ColumnAttribute.cs b/DynamORM/Mapper/ColumnAttribute.cs index 750dcea..6209676 100644 --- a/DynamORM/Mapper/ColumnAttribute.cs +++ b/DynamORM/Mapper/ColumnAttribute.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/DynamicCast.cs b/DynamORM/Mapper/DynamicCast.cs index 1bd75ba..d3504a9 100644 --- a/DynamORM/Mapper/DynamicCast.cs +++ b/DynamORM/Mapper/DynamicCast.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/DynamicMapperCache.cs b/DynamORM/Mapper/DynamicMapperCache.cs index 59b08c7..994a51a 100644 --- a/DynamORM/Mapper/DynamicMapperCache.cs +++ b/DynamORM/Mapper/DynamicMapperCache.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/DynamicPropertyInvoker.cs b/DynamORM/Mapper/DynamicPropertyInvoker.cs index 047ca2d..328f342 100644 --- a/DynamORM/Mapper/DynamicPropertyInvoker.cs +++ b/DynamORM/Mapper/DynamicPropertyInvoker.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/DynamicTypeMap.cs b/DynamORM/Mapper/DynamicTypeMap.cs index be2604c..c5caa5e 100644 --- a/DynamORM/Mapper/DynamicTypeMap.cs +++ b/DynamORM/Mapper/DynamicTypeMap.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/IgnoreAttribute.cs b/DynamORM/Mapper/IgnoreAttribute.cs index fe4e917..ef55f87 100644 --- a/DynamORM/Mapper/IgnoreAttribute.cs +++ b/DynamORM/Mapper/IgnoreAttribute.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Mapper/TableAttribute.cs b/DynamORM/Mapper/TableAttribute.cs index dcce1c4..d290bec 100644 --- a/DynamORM/Mapper/TableAttribute.cs +++ b/DynamORM/Mapper/TableAttribute.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/DynamORM/Properties/AssemblyInfo.cs b/DynamORM/Properties/AssemblyInfo.cs index 492f39d..5629316 100644 --- a/DynamORM/Properties/AssemblyInfo.cs +++ b/DynamORM/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * DynamORM - Dynamic Object-Relational Mapping library. - * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com) + * Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without