diff --git a/Tortuga.Chain/Changelog.md b/Tortuga.Chain/Changelog.md index 9a362e6f5..fb6de63b7 100644 --- a/Tortuga.Chain/Changelog.md +++ b/Tortuga.Chain/Changelog.md @@ -1,3 +1,65 @@ +## Version 4.1 + + +### Features with Breaking Changes + +[#440 Default Sorting for WithLimits](https://github.com/TortugaResearch/Chain/issues/440) + +If you use WithLimits without a sort order, then it will act non-deterministically. This is because the database could sort the results in any random order if not constrained. + +The fix is to default to sorting with primary key when using WithLimits. If there are no primary keys and no explicit sorting, then an exception will be thrown if in strict mode. + +This change also affects table-valued functions. Except these cannot infer the sort order as they do not have a primary key. + +For reflection-based scenarios, the method `TableOrViewMetadata.GetDefaultSortOrder(int)` can be used to get a table's default sort order. + +### Features + +[#459 Add TimeSpan support for Access and OleDB](https://github.com/TortugaResearch/Tortuga.Chain/issues/459) + + +Access doesn't understand TimeSpan at all and treats it as a DateTime. + +OleDB for SQL Server is worse. It returns time(7) columns as strings with the column type set to object. + + +[#445 Add support for DateOnly and TimeOnly](https://github.com/TortugaResearch/Tortuga.Chain/issues/445) + +On the parameter builder side, `DateOnly` and `TimeOnly` need to be converted into `DateTime` or `TimeSpan`. Which specific conversion is used depends on the database/driver combination. + +On the materializer side, a new class called `MaterializerTypeConverter` will be used. Moving forward, this will handle type conversions from the result set to the object. + +The `MaterializerTypeConverter` is owned by a `DatabaseMetadata` object, allowing additional conversions to be registered at runtime. + +[#451 Add support for CommitAsync, Save(savepointName), SaveAsync(savepointName), Rollback(savepointName), and RollbackAsync](https://github.com/TortugaResearch/Chain/issues/451) + +We are only exposing these for .NET 6 and later. + +[#443 GetByKey, UpdateByKey, and DeleteByKey should support System.Int16](https://github.com/TortugaResearch/Chain/issues/443) + +This was done to improve support for lookup tables with small keys. + +### Bug Fixes + +The OleDB version of SQL Server was truncating fractional seconds when the parameter type is `time(n)` and `n>0`. To fix this, we have to force it to use `DateTime/DBTimeStamp` instead of `TimeSpan/DBTime`. + +[#465 OleDbSqlServerTableFunction doesn't support sorting with table limits](https://github.com/TortugaResearch/Tortuga.Chain/issues/465) + + +Using either works, but there is an error if both are used. + + +### Performance Enhancements + +[#439 Use `SqlCommand.EnableOptimizedParameterBinding` in SQL Server MDS.](https://github.com/TortugaResearch/Chain/issues/439) + + +### Technical Debt + +Added test case for command timeout. + +Created `ExecutionToken.PopulateCommand` method. This eliminates a lot of copy & past text from the various `Execute`/`ExecuteAsync` methods. + ## Version 4.0 ### Architecture diff --git a/Tortuga.Chain/Engineering Notes.md b/Tortuga.Chain/Engineering Notes.md new file mode 100644 index 000000000..ddad1b1ce --- /dev/null +++ b/Tortuga.Chain/Engineering Notes.md @@ -0,0 +1,21 @@ +## Generics + +When multiple generic parameters are needed, they should always be in this order. + + +``` + + where TConnection : DbConnection + where TTransaction : DbTransaction + where TCommand : DbCommand + where TParameter : DbParameter + where TObjectName : struct + where TDbType : struct +``` + +When used... + +``` + +``` + diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`2.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`2.cs index f8070bfde..509632d07 100644 --- a/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`2.cs +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`2.cs @@ -3,8 +3,6 @@ namespace Traits; - - interface ICommandHelper : IDataSource where TObjectName : struct where TDbType : struct diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`4.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`4.cs index c8b14e81a..74066fad1 100644 --- a/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`4.cs +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/ICommandHelper`4.cs @@ -3,7 +3,6 @@ namespace Traits; - interface ICommandHelper : ICommandHelper where TCommand : DbCommand where TParameter : DbParameter @@ -11,4 +10,4 @@ interface ICommandHelper : ICommandH where TDbType : struct { List GetParameters(SqlBuilder builder); -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/IGetByKeyHelper`4.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/IGetByKeyHelper`4.cs index 5859720a5..957ecd96e 100644 --- a/Tortuga.Chain/Shared/DataSource/CommandBuilders/IGetByKeyHelper`4.cs +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/IGetByKeyHelper`4.cs @@ -10,13 +10,10 @@ interface IGetByKeyHelper : ICommand where TObjectName : struct where TDbType : struct { - SingleRowDbCommandBuilder OnGetByKey(TObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder OnGetByKey(TObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class; MultipleRowDbCommandBuilder OnGetByKeyList(TObjectName tableName, ColumnMetadata keyColumn, IEnumerable keys) where TObject : class; } -} - - - +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsDeleteAllTrait`2.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsDeleteAllTrait`2.cs index cde8b1a4a..9ad9a4ed4 100644 --- a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsDeleteAllTrait`2.cs +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsDeleteAllTrait`2.cs @@ -1,13 +1,15 @@ -using Tortuga.Chain; +using System.Data.Common; +using Tortuga.Chain; using Tortuga.Chain.DataSources; using Tortuga.Shipwright; namespace Traits; [Trait] -class SupportsDeleteAllTrait : ISupportsDeleteAll +class SupportsDeleteAllTrait : ISupportsDeleteAll where TObjectName : struct where TDbType : struct + where TParameter : DbParameter { [Partial("tableName")] public Func> OnDeleteAll { get; set; } = null!; @@ -30,6 +32,5 @@ class SupportsDeleteAllTrait : ISupportsDeleteAll ILink ISupportsDeleteAll.DeleteAll(string tableName) => OnDeleteAll(DataSource.DatabaseMetadata.ParseObjectName(tableName)); - ILink ISupportsDeleteAll.DeleteAll() => DeleteAll(); -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByColumnListTrait`4.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByColumnListTrait`4.cs new file mode 100644 index 000000000..833698201 --- /dev/null +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByColumnListTrait`4.cs @@ -0,0 +1,326 @@ +using System.ComponentModel; +using System.Data.Common; +using System.Diagnostics.CodeAnalysis; +using Tortuga.Chain; +using Tortuga.Chain.CommandBuilders; +using Tortuga.Chain.DataSources; +using Tortuga.Chain.Metadata; +using Tortuga.Shipwright; + +namespace Traits; + +[Trait] +class SupportsGetByColumnListTrait : ISupportsGetByColumnList, ISupportsGetByColumn + where TCommand : DbCommand + where TParameter : DbParameter + where TObjectName : struct + where TDbType : struct +{ + [Container(RegisterInterface = true)] + internal IGetByKeyHelper DataSource { get; set; } = null!; + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string tableName, string columnName, TKey key) + { + return GetByColumn(DataSource.DatabaseMetadata.ParseObjectName(tableName), columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string tableName, string columnName, string key) + { + return GetByColumn(DataSource.DatabaseMetadata.ParseObjectName(tableName), columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string columnName, TKey key) + where TObject : class + { + return GetByColumn(columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string columnName, string key) + where TObject : class + { + return GetByColumn(columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string columnName, short key) + where TObject : class + { + return GetByColumn(columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string columnName, int key) + where TObject : class + { + return GetByColumn(columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string columnName, long key) + where TObject : class + { + return GetByColumn(columnName, key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumn.GetByColumn(string columnName, Guid key) + where TObject : class + { + return GetByColumn(columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(string columnName, Guid key) + where TObject : class + { + return GetByColumnCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(string columnName, long key) + where TObject : class + { + return GetByColumnCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(string columnName, short key) + where TObject : class + { + return GetByColumnCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(string columnName, int key) + where TObject : class + { + return GetByColumnCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(string columnName, string key) + where TObject : class + { + return GetByColumnCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. + /// The type of the key. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(string columnName, TKey key) + where TObject : class + { + return GetByColumnCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// Name of the table. + /// The name of the column to search. + /// The search key. + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(TObjectName tableName, string columnName, string key) + { + return GetByColumn(tableName, columnName, key); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// + /// Name of the table. + /// The name of the column to search. + /// The search key. + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GetByColumn")] + [Expose] + public MultipleRowDbCommandBuilder GetByColumn(TObjectName tableName, string columnName, TKey key) + { + var primaryKeys = DataSource.DatabaseMetadata.GetTableOrView(tableName).Columns.Where(c => c.SqlName.Equals(columnName, StringComparison.OrdinalIgnoreCase)).ToList(); + + if (primaryKeys.Count == 0) + throw new MappingException($"Cannot find a column named {columnName} on table {tableName}."); + + return DataSource.OnGetByKey(tableName, primaryKeys.Single(), key); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumnList.GetByColumnList(string tableName, string columnName, IEnumerable keys) + { + return GetByColumnList(DataSource.DatabaseMetadata.ParseObjectName(tableName), columnName, keys); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumnList.GetByColumnList(string columnName, IEnumerable keys) + { + return GetByColumnList(columnName, keys); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumnList.GetByColumnList(string columnName, IEnumerable keys) + { + return GetByColumnList(columnName, keys); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumnList.GetByColumnList(string columnName, IEnumerable keys) + { + return GetByColumnList(columnName, keys); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumnList.GetByColumnList(string columnName, IEnumerable keys) + { + return GetByColumnList(columnName, keys); + } + + IMultipleRowDbCommandBuilder ISupportsGetByColumnList.GetByColumnList(string columnName, IEnumerable keys) + { + return GetByColumnList(columnName, keys); + } + + /// + /// Gets a set of records by their primary key. + /// + /// + /// Name of the table. + /// The name of the column to search. + /// The search keys. + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GetByColumnList")] + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(TObjectName tableName, string columnName, IEnumerable keys) + { + return GetByColumnListCore(tableName, columnName, keys); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the returned object. + /// The type of the key. + /// The name of the column to search. + /// The search keys. + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class + { + return GetByColumnListCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, columnName, keys); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the returned object. + /// The name of the column to search. + /// The search keys. + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class + { + return GetByColumnList(columnName, keys); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the returned object. + /// The name of the column to search. + /// The search keys. + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class + { + return GetByColumnList(columnName, keys); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the returned object. + /// The name of the column to search. + /// The search keys. + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class + { + return GetByColumnList(columnName, keys); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the returned object. + /// The name of the column to search. + /// The search keys. + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class + { + return GetByColumnList(columnName, keys); + } + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the returned object. + /// The name of the column to search. + /// The search keys. + [Expose] + public MultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class + { + return GetByColumnList(columnName, keys); + } + + #region Core Functions + + MultipleRowDbCommandBuilder GetByColumnCore(TObjectName tableName, string columnName, TKey key) +where TObject : class + { + var primaryKeys = DataSource.DatabaseMetadata.GetTableOrView(tableName).Columns.Where(c => c.SqlName.Equals(columnName, StringComparison.OrdinalIgnoreCase)).ToList(); + + if (primaryKeys.Count == 0) + throw new MappingException($"Cannot find a column named {columnName} on table {tableName}."); + + return new MultipleRowDbCommandBuilder(DataSource.OnGetByKey(tableName, primaryKeys.Single(), key)); + } + + MultipleRowDbCommandBuilder GetByColumnListCore(TObjectName tableName, string columnName, IEnumerable keys) + where TObject : class + { + var primaryKeys = DataSource.DatabaseMetadata.GetTableOrView(tableName).Columns.Where(c => c.SqlName.Equals(columnName, StringComparison.OrdinalIgnoreCase)).ToList(); + + if (primaryKeys.Count == 0) + throw new MappingException($"Cannot find a column named {columnName} on table {tableName}."); + + return new MultipleRowDbCommandBuilder(DataSource.OnGetByKeyList(tableName, primaryKeys.Single(), keys)); + } + + #endregion Core Functions +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByKeyListTrait`4.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByKeyListTrait`4.cs index 6d09169f8..7b38a67fa 100644 --- a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByKeyListTrait`4.cs +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsGetByKeyListTrait`4.cs @@ -41,6 +41,12 @@ ISingleRowDbCommandBuilder ISupportsGetByKey.GetByKey(string k return GetByKey(key); } + ISingleRowDbCommandBuilder ISupportsGetByKey.GetByKey(short key) + where TObject : class + { + return GetByKey(key); + } + ISingleRowDbCommandBuilder ISupportsGetByKey.GetByKey(int key) where TObject : class { @@ -59,7 +65,6 @@ ISingleRowDbCommandBuilder ISupportsGetByKey.GetByKey(Guid key return GetByKey(key); } - /// /// Gets a record by its primary key. /// @@ -88,6 +93,20 @@ public SingleRowDbCommandBuilder GetByKey(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, key); } + /// + /// Gets a record by its primary key. + /// + /// The type of the object. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + [Expose] + public SingleRowDbCommandBuilder GetByKey(short key) + where TObject : class + { + return GetByKeyCore(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, key); + } + /// /// Gets a record by its primary key. /// @@ -159,42 +178,36 @@ public SingleRowDbCommandBuilder GetByKey(TObjectNam return DataSource.OnGetByKey(tableName, primaryKeys.Single(), key); } - - IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(string tableName, IEnumerable keys) { return GetByKeyList(DataSource.DatabaseMetadata.ParseObjectName(tableName), keys); } - - IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(IEnumerable keys) { return GetByKeyList(keys); } - + IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(IEnumerable keys) + { + return GetByKeyList(keys); + } IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(IEnumerable keys) { return GetByKeyList(keys); } - - IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(IEnumerable keys) { return GetByKeyList(keys); } - - IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(IEnumerable keys) { return GetByKeyList(keys); } - /// /// Gets a set of records by their primary key. /// @@ -210,8 +223,6 @@ public MultipleRowDbCommandBuilder GetByKeyList(TObj return GetByKeyListCore(tableName, keys); } - - /// /// Gets a set of records by a key list. /// @@ -225,8 +236,6 @@ public MultipleRowDbCommandBuilder GetByKeyList(DataSource.DatabaseMetadata.GetTableOrViewFromClass(OperationType.Select).Name, keys); } - - /// /// Gets a set of records by a key list. /// @@ -239,8 +248,6 @@ public MultipleRowDbCommandBuilder GetByKeyList(keys); } - - /// /// Gets a set of records by a key list. /// @@ -253,6 +260,18 @@ public MultipleRowDbCommandBuilder GetByKeyList(keys); } + /// + /// Gets a set of records by a key list. + /// + /// The type of the returned object. + /// The keys. + [Expose] + public MultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) + where TObject : class + { + return GetByKeyList(keys); + } + /// /// Gets a set of records by a key list. /// @@ -265,8 +284,6 @@ public MultipleRowDbCommandBuilder GetByKeyList(keys); } - - /// /// Gets a set of records by a key list. /// @@ -279,11 +296,29 @@ public MultipleRowDbCommandBuilder GetByKeyList(keys); } + #region Core Functions + IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(string tableName, string keyColumn, IEnumerable keys) + { + return GetByKeyListCore(DataSource.DatabaseMetadata.ParseObjectName(tableName), keyColumn, keys); + } + + /// Gets a set of records by an unique key. + /// The type of the t key. + /// Name of the table. + /// Name of the key column. This should be a primary or unique key, but that's not enforced. + /// The keys. + /// IMultipleRowDbCommandBuilder. + [Obsolete("This will be replaced by GetByColumn")] + [EditorBrowsable(EditorBrowsableState.Never)] + [Expose] + public MultipleRowDbCommandBuilder GetByKeyList(string tableName, string keyColumn, IEnumerable keys) + { + return GetByKeyListCore(DataSource.DatabaseMetadata.ParseObjectName(tableName), keyColumn, keys); + } - #region Core Functions SingleRowDbCommandBuilder GetByKeyCore(TObjectName tableName, TKey key) - where TObject : class + where TObject : class { var primaryKeys = DataSource.DatabaseMetadata.GetTableOrView(tableName).PrimaryKeyColumns; @@ -330,27 +365,6 @@ MultipleRowDbCommandBuilder GetByKeyListCore(DataSource.OnGetByKeyList(tableName, primaryKeys.Single(), keys)); } - IMultipleRowDbCommandBuilder ISupportsGetByKeyList.GetByKeyList(string tableName, string keyColumn, IEnumerable keys) - { - return GetByKeyListCore(DataSource.DatabaseMetadata.ParseObjectName(tableName), keyColumn, keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [Obsolete("This will be replaced by GetByColumn")] - [EditorBrowsable(EditorBrowsableState.Never)] - - [Expose] - public MultipleRowDbCommandBuilder GetByKeyList(string tableName, string keyColumn, IEnumerable keys) - { - return GetByKeyListCore(DataSource.DatabaseMetadata.ParseObjectName(tableName), keyColumn, keys); - } - - //TODO-441 GetByColumn MultipleRowDbCommandBuilder GetByKeyListCore(TObjectName tableName, string keyColumn, IEnumerable keys) where TObject : class @@ -363,8 +377,5 @@ MultipleRowDbCommandBuilder GetByKeyListCore(DataSource.OnGetByKeyList(tableName, primaryKeys.Single(), keys)); } - #endregion -} - - - + #endregion Core Functions +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsTruncateTrait`2.cs b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsTruncateTrait`2.cs index a3f77bdf5..8e6c83b51 100644 --- a/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsTruncateTrait`2.cs +++ b/Tortuga.Chain/Shared/DataSource/CommandBuilders/SupportsTruncateTrait`2.cs @@ -1,14 +1,15 @@ -using Tortuga.Chain; +using System.Data.Common; +using Tortuga.Chain; using Tortuga.Chain.DataSources; using Tortuga.Shipwright; namespace Traits; - [Trait] -class SupportsTruncateTrait : ISupportsTruncate +class SupportsTruncateTrait : ISupportsTruncate where TObjectName : struct where TDbType : struct + where TParameter : DbParameter { [Partial("tableName")] public Func> OnTruncate { get; set; } = null!; @@ -32,6 +33,4 @@ class SupportsTruncateTrait : ISupportsTruncate ILink ISupportsTruncate.Truncate(string tableName) => OnTruncate(DataSource.DatabaseMetadata.ParseObjectName(tableName)); ILink ISupportsTruncate.Truncate() => Truncate(); -} - - +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/OpenDataSourceTrait`5.cs b/Tortuga.Chain/Shared/DataSource/OpenDataSourceTrait`5.cs index 6bf5205bd..dca48ae79 100644 --- a/Tortuga.Chain/Shared/DataSource/OpenDataSourceTrait`5.cs +++ b/Tortuga.Chain/Shared/DataSource/OpenDataSourceTrait`5.cs @@ -8,8 +8,6 @@ namespace Traits { - - [Trait] class OpenDataSourceTrait : IOpenDataSource where TRootDataSource : class, IRootDataSource, IDataSource, IHasExtensionCache @@ -19,7 +17,6 @@ class OpenDataSourceTrait m_Transaction; - - - /// /// The extension cache is used by extensions to store data source specific information. /// @@ -54,7 +48,6 @@ public ConcurrentDictionary ExtensionCache get { return m_BaseDataSource.ExtensionCache; } } - /// /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. /// @@ -73,7 +66,6 @@ public TDatabaseMetadata DatabaseMetadata get { return (TDatabaseMetadata)m_BaseDataSource.DatabaseMetadata; } } - /// /// Closes the connection and transaction associated with this data source. /// @@ -106,7 +98,6 @@ public async Task TestConnectionAsync() await cmd.ExecuteScalarAsync().ConfigureAwait(false); } - /// /// Tries the commit the transaction associated with this data source. /// @@ -120,9 +111,8 @@ public bool TryCommit() return true; } - /// - /// Tries the rollback the transaction associated with this data source. + /// Tries to rollback the transaction associated with this data source. /// /// True if there was an open transaction associated with this data source, otherwise false. [Expose] @@ -134,7 +124,6 @@ public bool TryRollback() return true; } - /// /// Returns the associated connection. /// @@ -152,8 +141,6 @@ public bool TryRollback() [Partial("additionalRules,userValue")] public Func?, object?, TOpenDataSource> OnOverride { get; set; } = null!; - - /// /// Modifies this data source with additional audit rules. /// @@ -190,5 +177,98 @@ public TOpenDataSource WithUser(object? userValue) return OnOverride(null, userValue); } +#if NET6_0_OR_GREATER + /// + /// Tries to commits the transaction and disposes the underlying connection. + /// + /// True if there was an open transaction associated with this data source, otherwise false. + [Expose] + public async Task TryCommitAsync(CancellationToken cancellationToken = default) + { + if (m_Transaction == null) + return false; + + await m_Transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + + return true; + } + + /// + /// Tries to roll back the transaction. + /// + /// True if there was an open transaction associated with this data source, otherwise false. + [Expose] + public async Task TryRollbackAsync(CancellationToken cancellationToken = default) + { + if (m_Transaction == null) + return false; + + await m_Transaction.RollbackAsync(cancellationToken).ConfigureAwait(false); + + return true; + } + + /// + /// Tries to roll back the transaction to the indicated save point. + /// + /// The name of the savepoint to roll back to. + /// + /// True if there was an open transaction associated with this data source, otherwise false. + [Expose] + public async Task TryRollbackAsync(string savepointName, CancellationToken cancellationToken = default) + { + if (m_Transaction == null) + return false; + + await m_Transaction.RollbackAsync(savepointName).ConfigureAwait(false); + return true; + } + + /// + /// Tries to creates a savepoint in the transaction. This allows all commands that are executed after the savepoint was established to be rolled back, restoring the transaction state to what it was at the time of the savepoint. + /// + /// The name of the savepoint to be created. + /// + /// True if there was an open transaction associated with this data source, otherwise false. + [Expose] + public async Task TrySaveAsync(string savepointName, CancellationToken cancellationToken = default) + { + if (m_Transaction == null) + return false; + + await m_Transaction.SaveAsync(savepointName, cancellationToken).ConfigureAwait(false); + return true; + } + + /// + /// Tries to roll back the transaction to the indicated save point. + /// + /// The name of the savepoint to roll back to. + /// True if there was an open transaction associated with this data source, otherwise false. + [Expose] + public bool TryRollback(string savepointName) + { + if (m_Transaction == null) + return false; + + m_Transaction.Rollback(savepointName); + return true; + } + + /// + /// Tries to create a savepoint in the transaction. This allows all commands that are executed after the savepoint was established to be rolled back, restoring the transaction state to what it was at the time of the savepoint. + /// + /// The name of the savepoint to be created. + /// True if there was an open transaction associated with this data source, otherwise false. + [Expose] + public bool TrySave(string savepointName) + { + if (m_Transaction == null) + return false; + m_Transaction.Save(savepointName); + return true; + } + +#endif } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/DataSource/TransactionalDataSourceTrait`5.cs b/Tortuga.Chain/Shared/DataSource/TransactionalDataSourceTrait`5.cs index 443010c4e..550f5b84b 100644 --- a/Tortuga.Chain/Shared/DataSource/TransactionalDataSourceTrait`5.cs +++ b/Tortuga.Chain/Shared/DataSource/TransactionalDataSourceTrait`5.cs @@ -7,8 +7,6 @@ namespace Traits { - - [Trait] class TransactionalDataSourceTrait : ITransactionalDataSource, IDisposable where TRootDataSource : class, IRootDataSource, IDataSource, IHasExtensionCache @@ -17,25 +15,21 @@ class TransactionalDataSourceTrait /// Commits the transaction and disposes the underlying connection. /// @@ -97,6 +90,82 @@ public void Commit() Dispose(true); } +#if NET6_0_OR_GREATER + /// + /// Commits the transaction and disposes the underlying connection. + /// + [Expose] + public async Task CommitAsync(CancellationToken cancellationToken = default) + { + if (m_Disposed) + throw new ObjectDisposedException("Transaction is disposed"); + + await m_Transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + Dispose(true); + } + + /// + /// Rolls back the transaction and disposes the underlying connection. + /// + [Expose] + public async Task RollbackAsync(CancellationToken cancellationToken = default) + { + if (m_Disposed) + throw new ObjectDisposedException("Transaction is disposed"); + + await m_Transaction.RollbackAsync(cancellationToken).ConfigureAwait(false); + Dispose(true); + } + + /// + /// Rolls back the transaction to the indicated save point. + /// + /// The name of the savepoint to roll back to. + /// + [Expose] + public async Task RollbackAsync(string savepointName, CancellationToken cancellationToken = default) + { + if (m_Disposed) + throw new ObjectDisposedException("Transaction is disposed"); + + await m_Transaction.RollbackAsync(savepointName).ConfigureAwait(false); + } + + /// + /// Creates a savepoint in the transaction. This allows all commands that are executed after the savepoint was established to be rolled back, restoring the transaction state to what it was at the time of the savepoint. + /// + /// The name of the savepoint to be created. + /// + [Expose] + public async Task SaveAsync(string savepointName, CancellationToken cancellationToken = default) + { + await m_Transaction.SaveAsync(savepointName, cancellationToken).ConfigureAwait(false); + } + + /// + /// Rolls back the transaction to the indicated save point. + /// + /// The name of the savepoint to roll back to. + [Expose] + public void Rollback(string savepointName) + { + if (m_Disposed) + throw new ObjectDisposedException("Transaction is disposed"); + + m_Transaction.Rollback(savepointName); + } + + /// + /// Creates a savepoint in the transaction. This allows all commands that are executed after the savepoint was established to be rolled back, restoring the transaction state to what it was at the time of the savepoint. + /// + /// The name of the savepoint to be created. + [Expose] + public void Save(string savepointName) + { + m_Transaction.Save(savepointName); + } + +#endif /// /// Closes the current transaction and connection. If not committed, the transaction is rolled back. @@ -140,7 +209,6 @@ public ConcurrentDictionary ExtensionCache get { return m_BaseDataSource.ExtensionCache; } } - /// /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. /// @@ -150,7 +218,6 @@ public ICacheAdapter Cache get { return m_BaseDataSource.Cache; } } - /// /// Rolls back the transaction and disposes the underlying connection. /// @@ -164,7 +231,6 @@ public void Rollback() Dispose(true); } - /// /// Tests the connection. /// @@ -186,7 +252,6 @@ public async Task TestConnectionAsync() await cmd.ExecuteScalarAsync().ConfigureAwait(false); } - /// /// Gets the database metadata. /// @@ -196,4 +261,4 @@ public TDatabaseMetadata DatabaseMetadata get { return (TDatabaseMetadata)m_BaseDataSource.DatabaseMetadata; } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Shared/Legacy/MaybeNullWhenAttribute.cs b/Tortuga.Chain/Shared/Legacy/MaybeNullWhenAttribute.cs new file mode 100644 index 000000000..e335ce476 --- /dev/null +++ b/Tortuga.Chain/Shared/Legacy/MaybeNullWhenAttribute.cs @@ -0,0 +1,16 @@ +#if !NETCOREAPP3_1_OR_GREATER + +namespace System.Diagnostics.CodeAnalysis; + +[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +sealed class MaybeNullWhenAttribute : Attribute +{ + public MaybeNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + + public bool ReturnValue { get; } +} + +#endif diff --git a/Tortuga.Chain/Shared/Tests/Appenders/CommandTimeoutTests.cs b/Tortuga.Chain/Shared/Tests/Appenders/CommandTimeoutTests.cs new file mode 100644 index 000000000..3e8475791 --- /dev/null +++ b/Tortuga.Chain/Shared/Tests/Appenders/CommandTimeoutTests.cs @@ -0,0 +1,53 @@ +using Tortuga.Chain; + +namespace Tests.Appenders; + +#if SQL_SERVER_SDS +using System.Data.SqlClient; +#elif SQL_SERVER_MDS + +using Microsoft.Data.SqlClient; + +#endif + +#if (SQL_SERVER_SDS || SQL_SERVER_MDS) + +[TestClass] +public class CommandTimeoutTests : TestBase +{ + const string TimeoutSql = "WAITFOR DELAY '00:00:03'"; + + [DataTestMethod, RootData(DataSourceGroup.All)] + public void TimeoutTriggeredTest(string dataSourceName) + { + var dataSource = DataSource(dataSourceName); + try + { + dataSource.Sql(TimeoutSql).AsNonQuery().SetTimeout(TimeSpan.FromSeconds(2)).Execute(); + Assert.Fail("Timeout exception expected"); + } + catch (SqlException) {/* expected */} + finally + { + Release(dataSource); + } + } + + [DataTestMethod, RootData(DataSourceGroup.All)] + public async Task TimeoutTriggeredAsyncTest(string dataSourceName) + { + var dataSource = DataSource(dataSourceName); + try + { + await dataSource.Sql(TimeoutSql).AsNonQuery().SetTimeout(TimeSpan.FromSeconds(2)).ExecuteAsync(); + Assert.Fail("Timeout exception expected"); + } + catch (SqlException) {/* expected */} + finally + { + Release(dataSource); + } + } +} + +#endif \ No newline at end of file diff --git a/Tortuga.Chain/Shared/Tests/Appenders/SqlDependencyTests.cs b/Tortuga.Chain/Shared/Tests/Appenders/SqlDependencyTests.cs index 3d3256600..849dc9919 100644 --- a/Tortuga.Chain/Shared/Tests/Appenders/SqlDependencyTests.cs +++ b/Tortuga.Chain/Shared/Tests/Appenders/SqlDependencyTests.cs @@ -4,6 +4,14 @@ namespace Tests.Appenders; +#if SQL_SERVER_SDS +using System.Data.SqlClient; +#elif SQL_SERVER_MDS + +using Microsoft.Data.SqlClient; + +#endif + #if (SQL_SERVER_SDS || SQL_SERVER_MDS) [TestClass] @@ -124,4 +132,4 @@ public void SqlServerDataSourceTests_WithCaching(string dataSourceName) } } -#endif +#endif \ No newline at end of file diff --git a/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests.cs b/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests.cs index 1c64247ff..4bd053ef1 100644 --- a/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests.cs +++ b/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests.cs @@ -44,14 +44,6 @@ public void WriteToTableReadFromView(string dataSourceName, DataSourceType mode) } } - - - - - - - - [DataTestMethod, TablesAndViewData(DataSourceGroup.All)] public void ToDataTable(string dataSourceName, DataSourceType mode, string tableName) { @@ -60,7 +52,7 @@ public void ToDataTable(string dataSourceName, DataSourceType mode, string table { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = dataSource.From(tableName).WithLimits(10).ToDataTable().Execute(); + var result = dataSource.From(tableName).WithLimits(10).WithSorting(table.GetDefaultSortOrder()).ToDataTable().Execute(); Assert.IsTrue(result.Rows.Count <= 10); Assert.AreEqual(table.Columns.Count, result.Columns.Count); } @@ -78,7 +70,7 @@ public async Task ToDataTable_Async(string dataSourceName, DataSourceType mode, { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = await dataSource.From(tableName).WithLimits(10).ToDataTable().ExecuteAsync(); + var result = await dataSource.From(tableName).WithLimits(10).WithSorting(table.GetDefaultSortOrder()).ToDataTable().ExecuteAsync(); Assert.IsTrue(result.Rows.Count <= 10); Assert.AreEqual(table.Columns.Count, result.Columns.Count); } @@ -96,7 +88,7 @@ public void ToDataRow(string dataSourceName, DataSourceType mode, string tableNa { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = dataSource.From(tableName).WithLimits(1).ToDataRowOrNull().Execute(); + var result = dataSource.From(tableName).WithLimits(1).WithSorting(table.GetDefaultSortOrder()).ToDataRowOrNull().Execute(); if (result != null) { Assert.AreEqual(table.Columns.Count, result.Table.Columns.Count); @@ -116,7 +108,7 @@ public async Task ToDataRow_Async(string dataSourceName, DataSourceType mode, st { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = await dataSource.From(tableName).WithLimits(1).ToDataRowOrNull().ExecuteAsync(); + var result = await dataSource.From(tableName).WithLimits(1).WithSorting(table.GetDefaultSortOrder()).ToDataRowOrNull().ExecuteAsync(); if (result != null) { Assert.AreEqual(table.Columns.Count, result.Table.Columns.Count); @@ -136,7 +128,7 @@ public void ToTable(string dataSourceName, DataSourceType mode, string tableName { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = dataSource.From(tableName).WithLimits(10).ToTable().Execute(); + var result = dataSource.From(tableName).WithLimits(10).WithSorting(table.GetDefaultSortOrder()).ToTable().Execute(); Assert.IsTrue(result.Rows.Count <= 10); Assert.AreEqual(table.Columns.Count, result.ColumnNames.Count); } @@ -154,7 +146,7 @@ public async Task ToTable_Async(string dataSourceName, DataSourceType mode, stri { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = await dataSource.From(tableName).WithLimits(10).ToTable().ExecuteAsync(); + var result = await dataSource.From(tableName).WithLimits(10).WithSorting(table.GetDefaultSortOrder()).ToTable().ExecuteAsync(); Assert.IsTrue(result.Rows.Count <= 10); Assert.AreEqual(table.Columns.Count, result.ColumnNames.Count); } @@ -172,7 +164,7 @@ public void ToRow(string dataSourceName, DataSourceType mode, string tableName) { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = dataSource.From(tableName).WithLimits(1).ToRowOrNull().Execute(); + var result = dataSource.From(tableName).WithLimits(1).WithSorting(table.GetDefaultSortOrder()).ToRowOrNull().Execute(); if (result != null) { Assert.AreEqual(table.Columns.Count, result.Count); @@ -192,7 +184,7 @@ public async Task ToRow_Async(string dataSourceName, DataSourceType mode, string { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = await dataSource.From(tableName).WithLimits(1).ToRowOrNull().ExecuteAsync(); + var result = await dataSource.From(tableName).WithLimits(1).WithSorting(table.GetDefaultSortOrder()).ToRowOrNull().ExecuteAsync(); if (result != null) { Assert.AreEqual(table.Columns.Count, result.Count); @@ -256,20 +248,6 @@ public async Task ToTable_WithLimit_Async(string dataSourceName, DataSourceType } } - - - - - - - - - - - - - - [DataTestMethod, BasicData(DataSourceGroup.Primary)] public void FilterByObject(string dataSourceName, DataSourceType mode) { @@ -345,7 +323,6 @@ public void FilterByObject_Compiled_AutoTableSelection(string dataSourceName, Da } } - [DataTestMethod, BasicData(DataSourceGroup.Primary)] public void ImmutableArray(string dataSourceName, DataSourceType mode) { @@ -508,7 +485,28 @@ public void ToImmutableArray_NoDefaultConstructor(string dataSourceName, DataSou } } + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void FilterWithRecord(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + try + { + var emp1 = new EmployeeRecord() { FirstName = "A", LastName = "1" }; + var emp2 = new EmployeeRecord() { FirstName = "B", LastName = "2" }; + var emp3 = new EmployeeRecord() { FirstName = "C", LastName = "3" }; + var emp4 = new EmployeeRecord() { FirstName = "D", LastName = "4" }; + emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); + emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); + emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); + emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - + var find2 = dataSource.From(new EmployeeRecordFilter { EmployeeId = emp2.EmployeeId }).ToObject().Execute(); + Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); + } + finally + { + Release(dataSource); + } + } } diff --git a/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests_ToDynamic.cs b/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests_ToDynamic.cs index 1e14c4d73..bde55d6c3 100644 --- a/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests_ToDynamic.cs +++ b/Tortuga.Chain/Shared/Tests/CommandBuilders/FromTests_ToDynamic.cs @@ -3,7 +3,6 @@ [TestClass] public class FromTests_ToDynamic : TestBase { - [DataTestMethod, TablesAndViewData(DataSourceGroup.All)] public void ToDynamicCollection(string dataSourceName, DataSourceType mode, string tableName) { @@ -12,7 +11,7 @@ public void ToDynamicCollection(string dataSourceName, DataSourceType mode, stri { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = dataSource.From(tableName).WithLimits(10).ToDynamicCollection().Execute(); + var result = dataSource.From(tableName).WithLimits(10).WithSorting(table.GetDefaultSortOrder()).ToDynamicCollection().Execute(); Assert.IsTrue(result.Count <= 10); if (result.Count > 0) { @@ -34,7 +33,7 @@ public async Task ToDynamicCollection_Async(string dataSourceName, DataSourceTyp { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = await dataSource.From(tableName).WithLimits(10).ToDynamicCollection().ExecuteAsync(); + var result = await dataSource.From(tableName).WithLimits(10).WithSorting(table.GetDefaultSortOrder()).ToDynamicCollection().ExecuteAsync(); Assert.IsTrue(result.Count <= 10); if (result.Count > 0) { @@ -56,7 +55,7 @@ public void ToDynamicObject(string dataSourceName, DataSourceType mode, string t { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = dataSource.From(tableName).WithLimits(1).ToDynamicObjectOrNull().Execute(); + var result = dataSource.From(tableName).WithLimits(1).WithSorting(table.GetDefaultSortOrder()).ToDynamicObjectOrNull().Execute(); if (result != null) { var row = (IDictionary)result; @@ -77,7 +76,7 @@ public async Task ToDynamicObject_Async(string dataSourceName, DataSourceType mo { var table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - var result = await dataSource.From(tableName).WithLimits(1).ToDynamicObjectOrNull().ExecuteAsync(); + var result = await dataSource.From(tableName).WithLimits(1).WithSorting(table.GetDefaultSortOrder()).ToDynamicObjectOrNull().ExecuteAsync(); if (result != null) { var row = (IDictionary)result; @@ -89,4 +88,4 @@ public async Task ToDynamicObject_Async(string dataSourceName, DataSourceType mo Release(dataSource); } } -} \ No newline at end of file +} diff --git a/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByColumnTests.cs b/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByColumnTests.cs new file mode 100644 index 000000000..c60b70ce7 --- /dev/null +++ b/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByColumnTests.cs @@ -0,0 +1,60 @@ +using Tests.Models; + +namespace Tests.CommandBuilders; + +[TestClass] +public class GetByColumnTests : TestBase +{ + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void GetByColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + try + { + var reference = Guid.NewGuid().ToString(); + var emp1 = new Employee() { FirstName = "A", LastName = "1", Title = reference }; + var emp2 = new Employee() { FirstName = "B", LastName = "2", Title = reference }; + var emp3 = new Employee() { FirstName = "C", LastName = "3", Title = reference }; + var emp4 = new Employee() { FirstName = "D", LastName = "4", Title = reference }; + + emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); + emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); + emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); + emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); + + var find2 = dataSource.GetByColumn("Title", reference).ToCollection().Execute(); + Assert.AreEqual(4, find2.Count, "The wrong number of employees were returned"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void GetByColumnList(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + try + { + var reference1 = Guid.NewGuid().ToString(); + var reference2 = Guid.NewGuid().ToString(); + var emp1 = new Employee() { FirstName = "A", LastName = "1", Title = reference1 }; + var emp2 = new Employee() { FirstName = "B", LastName = "2", Title = reference1 }; + var emp3 = new Employee() { FirstName = "C", LastName = "3", Title = reference1 }; + var emp4 = new Employee() { FirstName = "D", LastName = "4", Title = reference2 }; + + emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); + emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); + emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); + emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); + + var find2 = dataSource.GetByColumnList("Title", new[] { reference1, reference2 }).ToCollection().Execute(); + Assert.AreEqual(4, find2.Count, "The wrong number of employees were returned"); + } + finally + { + Release(dataSource); + } + } +} diff --git a/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByKeyTests.cs b/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByKeyTests.cs index 8328271d8..085635d7b 100644 --- a/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByKeyTests.cs +++ b/Tortuga.Chain/Shared/Tests/CommandBuilders/GetByKeyTests.cs @@ -5,7 +5,6 @@ namespace Tests.CommandBuilders; [TestClass] public class GetByKeyTests : TestBase { - [DataTestMethod, BasicData(DataSourceGroup.Primary)] public void GetByKey(string dataSourceName, DataSourceType mode) { @@ -32,31 +31,7 @@ public void GetByKey(string dataSourceName, DataSourceType mode) } [DataTestMethod, BasicData(DataSourceGroup.Primary)] - public void GetByKeyWithRecord(string dataSourceName, DataSourceType mode) - { - var dataSource = DataSource(dataSourceName, mode); - try - { - var emp1 = new EmployeeRecord() { FirstName = "A", LastName = "1" }; - var emp2 = new EmployeeRecord() { FirstName = "B", LastName = "2" }; - var emp3 = new EmployeeRecord() { FirstName = "C", LastName = "3" }; - var emp4 = new EmployeeRecord() { FirstName = "D", LastName = "4" }; - - emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); - emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); - emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); - emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - - var find2 = dataSource.GetByKey(emp2.EmployeeKey.Value).ToObject().Execute(); - Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); - } - finally - { - Release(dataSource); - } - } - [DataTestMethod, BasicData(DataSourceGroup.Primary)] - public void GetByKeyWithTableAndView(string dataSourceName, DataSourceType mode) + public void GetByKeyList(string dataSourceName, DataSourceType mode) { var dataSource = DataSource(dataSourceName, mode); try @@ -71,8 +46,14 @@ public void GetByKeyWithTableAndView(string dataSourceName, DataSourceType mode) emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - var find2 = dataSource.GetByKey(emp2.EmployeeKey.Value).ToObject().Execute(); + var find2 = dataSource.GetByKey(EmployeeTableName, emp2.EmployeeKey.Value).ToObject().Execute(); Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); + + var list = dataSource.GetByKeyList(EmployeeTableName, new[] { emp2.EmployeeKey.Value, emp3.EmployeeKey.Value, emp4.EmployeeKey.Value }).ToCollection().Execute(); + Assert.AreEqual(3, list.Count, "GetByKeyList returned the wrong number of rows"); + Assert.IsTrue(list.Any(e => e.EmployeeKey == emp2.EmployeeKey)); + Assert.IsTrue(list.Any(e => e.EmployeeKey == emp3.EmployeeKey)); + Assert.IsTrue(list.Any(e => e.EmployeeKey == emp4.EmployeeKey)); } finally { @@ -81,26 +62,26 @@ public void GetByKeyWithTableAndView(string dataSourceName, DataSourceType mode) } [DataTestMethod, BasicData(DataSourceGroup.Primary)] - public void GetByKeyList(string dataSourceName, DataSourceType mode) + [Obsolete] + public void GetByKeyList_2(string dataSourceName, DataSourceType mode) { var dataSource = DataSource(dataSourceName, mode); try { - var emp1 = new Employee() { FirstName = "A", LastName = "1" }; - var emp2 = new Employee() { FirstName = "B", LastName = "2" }; - var emp3 = new Employee() { FirstName = "C", LastName = "3" }; - var emp4 = new Employee() { FirstName = "D", LastName = "4" }; + var emp1 = new Employee() { FirstName = "A", LastName = "1", Title = Guid.NewGuid().ToString() }; + var emp2 = new Employee() { FirstName = "B", LastName = "2", Title = Guid.NewGuid().ToString() }; + var emp3 = new Employee() { FirstName = "C", LastName = "3", Title = Guid.NewGuid().ToString() }; + var emp4 = new Employee() { FirstName = "D", LastName = "4", Title = Guid.NewGuid().ToString() }; emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - var find2 = dataSource.GetByKey(EmployeeTableName, emp2.EmployeeKey.Value).ToObject().Execute(); - Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); + //Pretend that Title is a unique column. - var list = dataSource.GetByKeyList(EmployeeTableName, new[] { emp2.EmployeeKey.Value, emp3.EmployeeKey.Value, emp4.EmployeeKey.Value }).ToCollection().Execute(); - Assert.AreEqual(3, list.Count, "GetByKeyList returned the wrong number of rows"); + var list = dataSource.GetByKeyList(EmployeeTableName, "Title", new[] { emp2.Title, emp3.Title, emp4.Title }).ToCollection().Execute(); + Assert.AreEqual(3, list.Count, "GetByKey returned the wrong number of rows"); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp2.EmployeeKey)); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp3.EmployeeKey)); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp4.EmployeeKey)); @@ -112,7 +93,7 @@ public void GetByKeyList(string dataSourceName, DataSourceType mode) } [DataTestMethod, BasicData(DataSourceGroup.Primary)] - public void GetByKeyListWithTableAndView(string dataSourceName, DataSourceType mode) + public void GetByKeyList_InferredTableName(string dataSourceName, DataSourceType mode) { var dataSource = DataSource(dataSourceName, mode); try @@ -127,11 +108,11 @@ public void GetByKeyListWithTableAndView(string dataSourceName, DataSourceType m emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - var find2 = dataSource.GetByKey(EmployeeTableName, emp2.EmployeeKey.Value).ToObject().Execute(); + var find2 = dataSource.GetByKey(emp2.EmployeeKey.Value).ToObject().Execute(); Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); - var list = dataSource.GetByKeyList(new[] { emp2.EmployeeKey.Value, emp3.EmployeeKey.Value, emp4.EmployeeKey.Value }).ToCollection().Execute(); - Assert.AreEqual(3, list.Count, "GetByKeyList returned the wrong number of rows"); + var list = dataSource.GetByKeyList(new[] { emp2.EmployeeKey.Value, emp3.EmployeeKey.Value, emp4.EmployeeKey.Value }).ToCollection().Execute(); + Assert.AreEqual(3, list.Count, "GetByKey returned the wrong number of rows"); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp2.EmployeeKey)); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp3.EmployeeKey)); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp4.EmployeeKey)); @@ -174,7 +155,7 @@ public void GetByKeyListWithRecord(string dataSourceName, DataSourceType mode) } [DataTestMethod, BasicData(DataSourceGroup.Primary)] - public void GetByKeyList_InferredTableName(string dataSourceName, DataSourceType mode) + public void GetByKeyListWithTableAndView(string dataSourceName, DataSourceType mode) { var dataSource = DataSource(dataSourceName, mode); try @@ -189,11 +170,11 @@ public void GetByKeyList_InferredTableName(string dataSourceName, DataSourceType emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - var find2 = dataSource.GetByKey(emp2.EmployeeKey.Value).ToObject().Execute(); + var find2 = dataSource.GetByKey(EmployeeTableName, emp2.EmployeeKey.Value).ToObject().Execute(); Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); - var list = dataSource.GetByKeyList(new[] { emp2.EmployeeKey.Value, emp3.EmployeeKey.Value, emp4.EmployeeKey.Value }).ToCollection().Execute(); - Assert.AreEqual(3, list.Count, "GetByKey returned the wrong number of rows"); + var list = dataSource.GetByKeyList(new[] { emp2.EmployeeKey.Value, emp3.EmployeeKey.Value, emp4.EmployeeKey.Value }).ToCollection().Execute(); + Assert.AreEqual(3, list.Count, "GetByKeyList returned the wrong number of rows"); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp2.EmployeeKey)); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp3.EmployeeKey)); Assert.IsTrue(list.Any(e => e.EmployeeKey == emp4.EmployeeKey)); @@ -205,34 +186,52 @@ public void GetByKeyList_InferredTableName(string dataSourceName, DataSourceType } [DataTestMethod, BasicData(DataSourceGroup.Primary)] - public void GetByKeyList_2(string dataSourceName, DataSourceType mode) + public void GetByKeyWithRecord(string dataSourceName, DataSourceType mode) { var dataSource = DataSource(dataSourceName, mode); try { - var emp1 = new Employee() { FirstName = "A", LastName = "1", Title = Guid.NewGuid().ToString() }; - var emp2 = new Employee() { FirstName = "B", LastName = "2", Title = Guid.NewGuid().ToString() }; - var emp3 = new Employee() { FirstName = "C", LastName = "3", Title = Guid.NewGuid().ToString() }; - var emp4 = new Employee() { FirstName = "D", LastName = "4", Title = Guid.NewGuid().ToString() }; + var emp1 = new EmployeeRecord() { FirstName = "A", LastName = "1" }; + var emp2 = new EmployeeRecord() { FirstName = "B", LastName = "2" }; + var emp3 = new EmployeeRecord() { FirstName = "C", LastName = "3" }; + var emp4 = new EmployeeRecord() { FirstName = "D", LastName = "4" }; + + emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); + emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); + emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); + emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); + + var find2 = dataSource.GetByKey(emp2.EmployeeKey.Value).ToObject().Execute(); + Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void GetByKeyWithTableAndView(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + try + { + var emp1 = new Employee() { FirstName = "A", LastName = "1" }; + var emp2 = new Employee() { FirstName = "B", LastName = "2" }; + var emp3 = new Employee() { FirstName = "C", LastName = "3" }; + var emp4 = new Employee() { FirstName = "D", LastName = "4" }; emp1 = dataSource.Insert(EmployeeTableName, emp1).ToObject().Execute(); emp2 = dataSource.Insert(EmployeeTableName, emp2).ToObject().Execute(); emp3 = dataSource.Insert(EmployeeTableName, emp3).ToObject().Execute(); emp4 = dataSource.Insert(EmployeeTableName, emp4).ToObject().Execute(); - //Pretend that Title is a unique column. - - var list = dataSource.GetByKeyList(EmployeeTableName, "Title", new[] { emp2.Title, emp3.Title, emp4.Title }).ToCollection().Execute(); - Assert.AreEqual(3, list.Count, "GetByKey returned the wrong number of rows"); - Assert.IsTrue(list.Any(e => e.EmployeeKey == emp2.EmployeeKey)); - Assert.IsTrue(list.Any(e => e.EmployeeKey == emp3.EmployeeKey)); - Assert.IsTrue(list.Any(e => e.EmployeeKey == emp4.EmployeeKey)); + var find2 = dataSource.GetByKey(emp2.EmployeeKey.Value).ToObject().Execute(); + Assert.AreEqual(emp2.EmployeeKey, find2.EmployeeKey, "The wrong employee was returned"); } finally { Release(dataSource); } } - - -} \ No newline at end of file +} diff --git a/Tortuga.Chain/Shared/Tests/CommandBuilders/InsertBulkTests.cs b/Tortuga.Chain/Shared/Tests/CommandBuilders/InsertBulkTests.cs index 0b2fcb31a..3b45645e6 100644 --- a/Tortuga.Chain/Shared/Tests/CommandBuilders/InsertBulkTests.cs +++ b/Tortuga.Chain/Shared/Tests/CommandBuilders/InsertBulkTests.cs @@ -212,6 +212,7 @@ public async Task InsertBulkAsync_Enumeration(string dataSourceName, DataSourceT #if SQL_SERVER_SDS || SQL_SERVER_MDS [DataTestMethod, BasicData(DataSourceGroup.Primary)] + [Obsolete] public void InsertBulk_IdentityInsert(string dataSourceName, DataSourceType mode) { var key1000 = Guid.NewGuid().ToString(); diff --git a/Tortuga.Chain/Shared/Tests/CommandBuilders/TableFunctionTests.cs b/Tortuga.Chain/Shared/Tests/CommandBuilders/TableFunctionTests.cs index 7e1b72c75..1a71d2c06 100644 --- a/Tortuga.Chain/Shared/Tests/CommandBuilders/TableFunctionTests.cs +++ b/Tortuga.Chain/Shared/Tests/CommandBuilders/TableFunctionTests.cs @@ -1,5 +1,4 @@ - -#if SQL_SERVER_SDS || SQL_SERVER_MDS +#if SQL_SERVER_SDS || SQL_SERVER_MDS using Tortuga.Chain.SqlServer; @@ -67,7 +66,9 @@ public void TableFunction1_Object_Limit(string dataSourceName, DataSourceType mo var dataSource = DataSource(dataSourceName, mode); try { - var result = dataSource.TableFunction(TableFunction1Name, Parameter1).WithLimits(1).ToTable().Execute(); + var table = dataSource.DatabaseMetadata.GetTableFunction(TableFunction1Name); + + var result = dataSource.TableFunction(TableFunction1Name, Parameter1).WithLimits(1).WithSorting(table.GetDefaultSortOrder(1)).ToTable().Execute(); } finally { diff --git a/Tortuga.Chain/Shared/Tests/Materializers/DateAndTimeOnlyTests.cs b/Tortuga.Chain/Shared/Tests/Materializers/DateAndTimeOnlyTests.cs new file mode 100644 index 000000000..0f4fa938b --- /dev/null +++ b/Tortuga.Chain/Shared/Tests/Materializers/DateAndTimeOnlyTests.cs @@ -0,0 +1,203 @@ +using Tests.Models; +using Tortuga.Chain; + +namespace Tests.Materializers; + +[TestClass] +public class DateAndTimeOnlyTests : TestBase +{ +#if MYSQL + + //Use a 1 second delta because MySQL doesn't support milliseconds. + const long TimeSpanDelta = TimeSpan.TicksPerSecond * 60; + +#else + const long TimeSpanDelta = TimeSpan.TicksPerSecond ; +#endif + +#if NET6_0_OR_GREATER + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToObject_DateOnlyColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var cust = new CustomerWithDate() { FullName = Guid.NewGuid().ToString(), State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + + var key = dataSource.Insert(CustomerTableName, cust).ToInt32().Execute(); + + var lookup = dataSource.GetByKey(CustomerTableName, key).ToObject().Execute(); + Assert.AreEqual(cust.BirthDay, lookup.BirthDay); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToObject_TimeOnlyColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var cust = new CustomerWithTime() { FullName = Guid.NewGuid().ToString(), State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + var key = dataSource.Insert(CustomerTableName, cust).ToInt32().Execute(); + + var lookup = dataSource.GetByKey(CustomerTableName, key).ToObject().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToCollection_DateOnlyColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var uniqueKey = Guid.NewGuid().ToString(); + var cust1 = new CustomerWithDate() { FullName = uniqueKey, State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + var cust2 = new CustomerWithDate() { FullName = uniqueKey, State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + var cust3 = new CustomerWithDate() { FullName = uniqueKey, State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + dataSource.Insert(CustomerTableName, cust1).Execute(); + dataSource.Insert(CustomerTableName, cust2).Execute(); + dataSource.Insert(CustomerTableName, cust3).Execute(); + + var lookup = dataSource.From(CustomerTableName, new { FullName = uniqueKey }).WithSorting("CustomerKey").ToCollection().Execute(); + Assert.AreEqual(cust1.BirthDay, lookup[0].BirthDay); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToCollection_TimeOnlyColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var uniqueKey = Guid.NewGuid().ToString(); + var cust1 = new CustomerWithTime() { FullName = uniqueKey, State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + var cust2 = new CustomerWithTime() { FullName = uniqueKey, State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + var cust3 = new CustomerWithTime() { FullName = uniqueKey, State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + dataSource.Insert(CustomerTableName, cust1).Execute(); + dataSource.Insert(CustomerTableName, cust2).Execute(); + dataSource.Insert(CustomerTableName, cust3).Execute(); + + var lookup = dataSource.From(CustomerTableName, new { FullName = uniqueKey }).WithSorting("CustomerKey").ToCollection().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToObject_DateOnlyColumn_Compiled(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var cust = new CustomerWithDate() { FullName = Guid.NewGuid().ToString(), State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + + var key = dataSource.Insert(CustomerTableName, cust).ToInt32().Execute(); + + var lookup = dataSource.GetByKey(CustomerTableName, key).Compile().ToObject().Execute(); + Assert.AreEqual(cust.BirthDay, lookup.BirthDay); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToObject_TimeOnlyColumn_Compiled(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var cust = new CustomerWithTime() { FullName = Guid.NewGuid().ToString(), State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + var key = dataSource.Insert(CustomerTableName, cust).ToInt32().Execute(); + + var lookup = dataSource.GetByKey(CustomerTableName, key).Compile().ToObject().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToCollection_DateOnlyColumn_Compiled(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var uniqueKey = Guid.NewGuid().ToString(); + var cust1 = new CustomerWithDate() { FullName = uniqueKey, State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + var cust2 = new CustomerWithDate() { FullName = uniqueKey, State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + var cust3 = new CustomerWithDate() { FullName = uniqueKey, State = "XX", BirthDay = DateOnly.FromDateTime(DateTime.Now) }; + dataSource.Insert(CustomerTableName, cust1).Execute(); + dataSource.Insert(CustomerTableName, cust2).Execute(); + dataSource.Insert(CustomerTableName, cust3).Execute(); + + var lookup = dataSource.From(CustomerTableName, new { FullName = uniqueKey }).WithSorting("CustomerKey").Compile().ToCollection().Execute(); + Assert.AreEqual(cust1.BirthDay, lookup[0].BirthDay); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToCollection_TimeOnlyColumn_Compiled(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var uniqueKey = Guid.NewGuid().ToString(); + var cust1 = new CustomerWithTime() { FullName = uniqueKey, State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + var cust2 = new CustomerWithTime() { FullName = uniqueKey, State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + var cust3 = new CustomerWithTime() { FullName = uniqueKey, State = "XX", PreferredCallTime = TimeOnly.FromDateTime(DateTime.Now) }; + dataSource.Insert(CustomerTableName, cust1).Execute(); + dataSource.Insert(CustomerTableName, cust2).Execute(); + dataSource.Insert(CustomerTableName, cust3).Execute(); + + var lookup = dataSource.From(CustomerTableName, new { FullName = uniqueKey }).WithSorting("CustomerKey").Compile().ToCollection().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + +#endif +} diff --git a/Tortuga.Chain/Shared/Tests/Materializers/TimeSpanTests.cs b/Tortuga.Chain/Shared/Tests/Materializers/TimeSpanTests.cs new file mode 100644 index 000000000..1b131fb29 --- /dev/null +++ b/Tortuga.Chain/Shared/Tests/Materializers/TimeSpanTests.cs @@ -0,0 +1,111 @@ +using Tests.Models; +using Tortuga.Chain; + +namespace Tests.Materializers; + +[TestClass] +public class TimeSpanTests : TestBase +{ +#if MYSQL + + //Use a 1 second delta because MySQL doesn't support milliseconds. + const long TimeSpanDelta = TimeSpan.TicksPerSecond * 60; + +#else + const long TimeSpanDelta = TimeSpan.TicksPerSecond; +#endif + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToObject_TimeSpanColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var cust = new CustomerWithTimeSpan() { FullName = Guid.NewGuid().ToString(), State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + var key = dataSource.Insert(CustomerTableName, cust).ToInt32().Execute(); + + var lookup = dataSource.GetByKey(CustomerTableName, key).ToObject().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToCollection_TimeSpanColumn(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var uniqueKey = Guid.NewGuid().ToString(); + var cust1 = new CustomerWithTimeSpan() { FullName = uniqueKey, State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + var cust2 = new CustomerWithTimeSpan() { FullName = uniqueKey, State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + var cust3 = new CustomerWithTimeSpan() { FullName = uniqueKey, State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + dataSource.Insert(CustomerTableName, cust1).Execute(); + dataSource.Insert(CustomerTableName, cust2).Execute(); + dataSource.Insert(CustomerTableName, cust3).Execute(); + + var lookup = dataSource.From(CustomerTableName, new { FullName = uniqueKey }).WithSorting("CustomerKey").ToCollection().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToObject_TimeSpanColumn_Compiled(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var cust = new CustomerWithTimeSpan() { FullName = Guid.NewGuid().ToString(), State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + var key = dataSource.Insert(CustomerTableName, cust).ToInt32().Execute(); + + var lookup = dataSource.GetByKey(CustomerTableName, key).Compile().ToObject().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust.PreferredCallTime.Ticks - lookup.PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } + + [DataTestMethod, BasicData(DataSourceGroup.Primary)] + public void ToCollection_TimeSpanColumn_Compiled(string dataSourceName, DataSourceType mode) + { + var dataSource = DataSource(dataSourceName, mode); + + try + { + var uniqueKey = Guid.NewGuid().ToString(); + var cust1 = new CustomerWithTimeSpan() { FullName = uniqueKey, State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + var cust2 = new CustomerWithTimeSpan() { FullName = uniqueKey, State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + var cust3 = new CustomerWithTimeSpan() { FullName = uniqueKey, State = "XX", PreferredCallTime = DateTime.Now.TimeOfDay }; + dataSource.Insert(CustomerTableName, cust1).Execute(); + dataSource.Insert(CustomerTableName, cust2).Execute(); + dataSource.Insert(CustomerTableName, cust3).Execute(); + + var lookup = dataSource.From(CustomerTableName, new { FullName = uniqueKey }).WithSorting("CustomerKey").Compile().ToCollection().Execute(); + + //To account for rounding, allow a 1 ms delta + Assert.IsTrue(cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks < TimeSpanDelta, $"Actual difference was {cust1.PreferredCallTime.Ticks - lookup[0].PreferredCallTime.Ticks}"); + } + finally + { + Release(dataSource); + } + } +} diff --git a/Tortuga.Chain/Shared/Tests/Models/Customer.cs b/Tortuga.Chain/Shared/Tests/Models/Customer.cs index 25724e35f..9097f9211 100644 --- a/Tortuga.Chain/Shared/Tests/Models/Customer.cs +++ b/Tortuga.Chain/Shared/Tests/Models/Customer.cs @@ -12,3 +12,30 @@ public class Customer public List Orders { get; } = new List(); } + +#if NET6_0_OR_GREATER +public class CustomerWithDate +{ + public int? CustomerKey { get; set; } + public string FullName { get; set; } + public string State { get; set; } + public DateOnly BirthDay { get; set; } +} + +public class CustomerWithTime +{ + public int? CustomerKey { get; set; } + public string FullName { get; set; } + public string State { get; set; } + public TimeOnly PreferredCallTime { get; set; } +} + +#endif + +public class CustomerWithTimeSpan +{ + public int? CustomerKey { get; set; } + public string FullName { get; set; } + public string State { get; set; } + public TimeSpan PreferredCallTime { get; set; } +} diff --git a/Tortuga.Chain/Shared/Tests/Models/Employee.cs b/Tortuga.Chain/Shared/Tests/Models/Employee.cs index 09d00de1e..e6ade3ea6 100644 --- a/Tortuga.Chain/Shared/Tests/Models/Employee.cs +++ b/Tortuga.Chain/Shared/Tests/Models/Employee.cs @@ -27,6 +27,14 @@ public class Employee public DateTime? UpdatedDate { get; set; } } + +[Table("Employee", Schema = "HR")] +public record EmployeeRecordFilter +{ + public string EmployeeId { get; set; } +} + + [Table("Employee", Schema = "HR")] public record EmployeeRecord { diff --git a/Tortuga.Chain/Shared/Tests/TestBase.Common.cs b/Tortuga.Chain/Shared/Tests/TestBase.Common.cs index 7dfe4b3e5..643d7409a 100644 --- a/Tortuga.Chain/Shared/Tests/TestBase.Common.cs +++ b/Tortuga.Chain/Shared/Tests/TestBase.Common.cs @@ -26,17 +26,21 @@ public T AttachTracers(T dataSource) where T : DataSource } #if CLASS_2 + public IAdvancedCrudDataSource DataSource2(string name, DataSourceType mode, [CallerMemberName] string caller = null) { return DataSource(name, mode, caller); } + #endif #if CLASS_3 + public AbstractDataSource DataSource3(string name, DataSourceType mode, [CallerMemberName] string caller = null) { return DataSource(name, mode, caller); } + #endif public void Release(IDataSource dataSource) @@ -84,7 +88,6 @@ private void CompiledMaterializers_MaterializerCompiled(object sender, Materiali WriteLine(e.Code); } - private void DefaultDispatcher_ExecutionCanceled(object sender, ExecutionEventArgs e) { //WriteLine("******"); @@ -121,20 +124,26 @@ static void BuildEmployeeSearchKey1000(IRootDataSource dataSource) { var trans = dataSource.BeginTransaction(); { - var cds = (ICrudDataSource)trans; - EmployeeSearchKey1000 = Guid.NewGuid().ToString(); - for (var i = 0; i < 1000; i++) - cds.Insert(EmployeeTableName, new Employee() { FirstName = i.ToString("0000"), LastName = "Z" + (int.MaxValue - i), Title = EmployeeSearchKey1000, MiddleName = i % 2 == 0 ? "A" + i : null }).ToObject().Execute(); - + BuildEmployeeSearchKey1000_NoTrans((ICrudDataSource)trans); trans.Commit(); } } - static void BuildEmployeeSearchKey1000_NoTrans(IRootDataSource dataSource) + static void BuildEmployeeSearchKey1000_NoTrans(ICrudDataSource dataSource) { EmployeeSearchKey1000 = Guid.NewGuid().ToString(); + var rows = new List(); + for (var i = 0; i < 1000; i++) - ((ICrudDataSource)dataSource).Insert(EmployeeTableName, new Employee() { FirstName = i.ToString("0000"), LastName = "Z" + (int.MaxValue - i), Title = EmployeeSearchKey1000, MiddleName = i % 2 == 0 ? "A" + i : null }).ToObject().Execute(); + rows.Add(new Employee() { FirstName = i.ToString("0000"), LastName = "Z" + (int.MaxValue - i), Title = EmployeeSearchKey1000, MiddleName = i % 2 == 0 ? "A" + i : null }); + + if (dataSource is ISupportsInsertBulk bulk) + bulk.InsertBulk(EmployeeTableName, rows).Execute(); + else if (dataSource is ISupportsInsertBatch batch) + batch.InsertMultipleBatch(EmployeeTableName, rows).Execute(); + else + foreach (var row in rows) + dataSource.Insert(EmployeeTableName, row).Execute(); } protected static string EmployeeSearchKey1000; diff --git a/Tortuga.Chain/SqlServerTestDatabase/Sales/Customer.sql b/Tortuga.Chain/SqlServerTestDatabase/Sales/Customer.sql index c4df38a5f..5a8f11f5b 100644 --- a/Tortuga.Chain/SqlServerTestDatabase/Sales/Customer.sql +++ b/Tortuga.Chain/SqlServerTestDatabase/Sales/Customer.sql @@ -1,18 +1,21 @@ CREATE TABLE Sales.Customer ( CustomerKey INT NOT NULL IDENTITY PRIMARY KEY, - FullName NVARCHAR(100) NULL, + FullName NVARCHAR(100) NULL, State Char(2) NOT NULL, - CreatedByKey INT NULL REFERENCES HR.Employee(EmployeeKey), - UpdatedByKey INT NULL REFERENCES HR.Employee(EmployeeKey), + CreatedByKey INT NULL REFERENCES HR.Employee(EmployeeKey), + UpdatedByKey INT NULL REFERENCES HR.Employee(EmployeeKey), CreatedDate DATETIME2 NULL, - UpdatedDate DATETIME2 NULL, + UpdatedDate DATETIME2 NULL, DeletedFlag BIT NOT NULL Default 0, DeletedDate DATETIME2 NULL, - DeletedByKey INT NULL REFERENCES HR.Employee(EmployeeKey) + DeletedByKey INT NULL REFERENCES HR.Employee(EmployeeKey), + + BirthDay Date NULL, + PreferredCallTime Time NULL ) diff --git a/Tortuga.Chain/Tortuga.Chain.Access.Tests/Setup.cs b/Tortuga.Chain/Tortuga.Chain.Access.Tests/Setup.cs index c39a0648a..7c35b800e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access.Tests/Setup.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access.Tests/Setup.cs @@ -72,7 +72,9 @@ CreatedDate DATETIME NULL DEFAULT NOW(), UpdatedDate DATETIME NULL, DeletedFlag BIT NOT NULL DEFAULT 0, DeletedDate DateTime NULL, - DeletedByKey INTEGER NULL + DeletedByKey INTEGER NULL, + BirthDay DATETIME NULL, + PreferredCallTime DATETIME NULL )"; const string sql3 = "CREATE VIEW EmployeeLookup AS SELECT FirstName, LastName, EmployeeKey, EmployeeId FROM Employee"; @@ -182,4 +184,4 @@ LocationName TEXT(100) NULL } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionMode.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionMode.cs index fb37e01ce..e6bae21c0 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionMode.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionMode.cs @@ -1,31 +1,23 @@ +namespace Tortuga.Chain.Access; - -namespace Tortuga.Chain.Access +/// +/// Used to chain together multiple statements. +/// +internal enum AccessCommandExecutionMode { - /// - /// Used to chain together multiple statements. + /// Pass the prepared command to the materializer for execution. /// - internal enum AccessCommandExecutionMode - { - /// - /// Pass the prepared command to the materializer for execution. - /// - Materializer = 0, - - /// - /// Run the prepared command directly, bypassing the materializer. - /// - /// This is usually used when chaining commands. - NonQuery = 1, - - /// - /// Reads a value using ExecuteScalar and passes the result to the next execution token - /// - ExecuteScalarAndForward = 2 - - - } + Materializer = 0, + /// + /// Run the prepared command directly, bypassing the materializer. + /// + /// This is usually used when chaining commands. + NonQuery = 1, + /// + /// Reads a value using ExecuteScalar and passes the result to the next execution token + /// + ExecuteScalarAndForward = 2 } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionToken.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionToken.cs index 56b0e8325..32cc04ca2 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionToken.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessCommandExecutionToken.cs @@ -2,40 +2,39 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +/// +/// Class AccessExecutionToken. +/// +public sealed class AccessCommandExecutionToken : CommandExecutionToken { /// - /// Class AccessExecutionToken. + /// Initializes a new instance of the class. /// - public sealed class AccessCommandExecutionToken : CommandExecutionToken + /// The data source. + /// Name of the operation. This is used for logging. + /// The SQL to be executed. + /// The parameters. + /// Type of the command. + public AccessCommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) + : base(dataSource, operationName, commandText, parameters, commandType) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. This is used for logging. - /// The SQL to be executed. - /// The parameters. - /// Type of the command. - public AccessCommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) - : base(dataSource, operationName, commandText, parameters, commandType) - { - } + } - internal AccessCommandExecutionMode ExecutionMode { get; set; } = AccessCommandExecutionMode.Materializer; + internal AccessCommandExecutionMode ExecutionMode { get; set; } = AccessCommandExecutionMode.Materializer; - /// - /// This function is executed with the value returned by this execution token. - /// It is used to create the next execution token in the chain. - /// - internal Action? ForwardResult { get; set; } + /// + /// This function is executed with the value returned by this execution token. + /// It is used to create the next execution token in the chain. + /// + internal Action? ForwardResult { get; set; } - /// - /// Gets or sets the command to be executed after the current execution token. - /// - /// - /// The chained command. - /// - internal AccessCommandExecutionToken? NextCommand { get; set; } - } + /// + /// Gets or sets the command to be executed after the current execution token. + /// + /// + /// The chained command. + /// + internal AccessCommandExecutionToken? NextCommand { get; set; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceBase.Traits.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceBase.Traits.cs index 137f6b96f..97e9982d0 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceBase.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceBase.Traits.cs @@ -10,7 +10,7 @@ namespace Tortuga.Chain.Access; -[UseTrait(typeof(SupportsDeleteAllTrait))] +[UseTrait(typeof(SupportsDeleteAllTrait))] [UseTrait(typeof(SupportsDeleteByKeyListTrait))] [UseTrait(typeof(SupportsUpdateTrait))] [UseTrait(typeof(SupportsDeleteTrait))] @@ -21,12 +21,12 @@ namespace Tortuga.Chain.Access; [UseTrait(typeof(SupportsDeleteSet))] [UseTrait(typeof(SupportsFromTrait))] [UseTrait(typeof(SupportsGetByKeyListTrait))] - +[UseTrait(typeof(SupportsGetByColumnListTrait))] partial class AccessDataSourceBase : ICrudDataSource { DatabaseMetadataCache ICommandHelper.DatabaseMetadata => DatabaseMetadata; - List ICommandHelper.GetParameters(SqlBuilder builder) => builder.GetParameters(); + List ICommandHelper.GetParameters(SqlBuilder builder) => builder.GetParameters(this); /// /// Delete multiple rows by key. @@ -104,7 +104,7 @@ TableDbCommandBuilder(this, tableOrViewName, filterValue, filterOptions); } - SingleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class { string where = keyColumn.SqlName + " = @Param0"; @@ -116,7 +116,6 @@ SingleRowDbCommandBuilder IGetByKeyHelper(this, tableName, where, parameters); - } MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKeyList(AbstractObjectName tableName, ColumnMetadata keyColumn, IEnumerable keys) where TObject : class @@ -200,4 +199,3 @@ private partial MultipleTableDbCommandBuilder OnSq return new AccessSqlCall(this, sqlStatement, argumentValue); } } - diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceSettings.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceSettings.cs index 252a9ac3f..890138905 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceSettings.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessDataSourceSettings.cs @@ -1,27 +1,26 @@ using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +/// +/// This class is used to modify settings that are not represented by the connection string. +/// +/// +public class AccessDataSourceSettings : DataSourceSettings { /// - /// This class is used to modify settings that are not represented by the connection string. + /// Initializes a new instance of the class. /// - /// - public class AccessDataSourceSettings : DataSourceSettings - { - /// - /// Initializes a new instance of the class. - /// - public AccessDataSourceSettings() { } + public AccessDataSourceSettings() { } - internal AccessDataSourceSettings(AccessDataSource dataSource, bool forwardEvents = false) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + internal AccessDataSourceSettings(AccessDataSource dataSource, bool forwardEvents = false) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - DefaultCommandTimeout = dataSource.DefaultCommandTimeout; - StrictMode = dataSource.StrictMode; - SequentialAccessMode = dataSource.SequentialAccessMode; - SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; - } + DefaultCommandTimeout = dataSource.DefaultCommandTimeout; + StrictMode = dataSource.StrictMode; + SequentialAccessMode = dataSource.SequentialAccessMode; + SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessMetadataCache.cs index 153048102..e9777ec3e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessMetadataCache.cs @@ -5,267 +5,266 @@ using Tortuga.Anchor; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +/// +/// Handles caching of metadata for various Access tables and views. +/// +public sealed class AccessMetadataCache : OleDbDatabaseMetadataCache { + readonly OleDbConnectionStringBuilder m_ConnectionBuilder; + readonly ConcurrentDictionary> m_Tables = new(); + readonly ConcurrentDictionary> m_TypeTableMap = new(); + + ConcurrentDictionary m_DataTableCache = new(); + bool m_SchemaLoaded; + /// - /// Handles caching of metadata for various Access tables and views. + /// Creates a new instance of /// - public sealed class AccessMetadataCache : OleDbDatabaseMetadataCache + /// The connection builder. + public AccessMetadataCache(OleDbConnectionStringBuilder connectionBuilder) { - readonly OleDbConnectionStringBuilder m_ConnectionBuilder; - readonly ConcurrentDictionary> m_Tables = new ConcurrentDictionary>(); - readonly ConcurrentDictionary> m_TypeTableMap = new ConcurrentDictionary>(); - - ConcurrentDictionary m_DataTableCache = new ConcurrentDictionary(); - bool m_SchemaLoaded; - - /// - /// Creates a new instance of - /// - /// The connection builder. - public AccessMetadataCache(OleDbConnectionStringBuilder connectionBuilder) - { - m_ConnectionBuilder = connectionBuilder; - } - - /// - /// Gets the indexes for a table. - /// - /// Name of the table. - /// - /// - /// This should be cached on a TableOrViewMetadata object. - /// - public override IndexMetadataCollection GetIndexesForTable(AccessObjectName tableName) - { - var result = new List>(); - var indexDT = GetSchemaTable(OleDbSchemaGuid.Indexes); + m_ConnectionBuilder = connectionBuilder; + } - var allColumns = GetTableOrView(tableName).Columns; - var indexes = indexDT.AsEnumerable().Where(r => string.Equals(r["TABLE_NAME"].ToString(), tableName.Name, StringComparison.Ordinal)).GroupBy(r => r["INDEX_NAME"].ToString()).ToList(); + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + /// https://stackoverflow.com/a/54149292/5274 + public override int? MaxParameters => 768; - foreach (var index in indexes) - { - var name = index.Key; - var unique = (bool)index.First()["UNIQUE"]; - var isPrimary = (bool)index.First()["PRIMARY_KEY"]; + /// + /// Gets the indexes for a table. + /// + /// Name of the table. + /// + /// + /// This should be cached on a TableOrViewMetadata object. + /// + public override IndexMetadataCollection GetIndexesForTable(AccessObjectName tableName) + { + var result = new List>(); + var indexDT = GetSchemaTable(OleDbSchemaGuid.Indexes); - var columns = new IndexColumnMetadata[index.Count()]; - foreach (var column in index) - { - var details = allColumns[(string)column["COLUMN_NAME"]]; - columns[(int)(long)column["ORDINAL_POSITION"] - 1] = new IndexColumnMetadata(details, false, false); - } + var allColumns = GetTableOrView(tableName).Columns; + var indexes = indexDT.AsEnumerable().Where(r => string.Equals(r["TABLE_NAME"].ToString(), tableName.Name, StringComparison.Ordinal)).GroupBy(r => r["INDEX_NAME"].ToString()).ToList(); - var indexType = isPrimary ? IndexType.Clustered : IndexType.Nonclustered; + foreach (var index in indexes) + { + var name = index.Key; + var unique = (bool)index.First()["UNIQUE"]; + var isPrimary = (bool)index.First()["PRIMARY_KEY"]; - result.Add(new IndexMetadata(tableName, name, isPrimary, unique, false, new IndexColumnMetadataCollection(columns), null, null, indexType)); + var columns = new IndexColumnMetadata[index.Count()]; + foreach (var column in index) + { + var details = allColumns[(string)column["COLUMN_NAME"]]; + columns[(int)(long)column["ORDINAL_POSITION"] - 1] = new IndexColumnMetadata(details, false, false); } - return new IndexMetadataCollection(result); + var indexType = isPrimary ? IndexType.Clustered : IndexType.Nonclustered; + + result.Add(new IndexMetadata(tableName, name, isPrimary, unique, false, new IndexColumnMetadataCollection(columns), null, null, indexType)); } - /// - /// Gets the metadata for a table or view. - /// - /// - /// - public override TableOrViewMetadata GetTableOrView(AccessObjectName tableName) - { - if (!m_SchemaLoaded) - Preload(); + return new IndexMetadataCollection(result); + } - TableOrViewMetadata? result; - if (m_Tables.TryGetValue(tableName, out result)) - return result; + /// + /// Gets the metadata for a table or view. + /// + /// + /// + public override TableOrViewMetadata GetTableOrView(AccessObjectName tableName) + { + if (!m_SchemaLoaded) + Preload(); - throw new MissingObjectException($"Could not find table or view {tableName}"); - } + TableOrViewMetadata? result; + if (m_Tables.TryGetValue(tableName, out result)) + return result; - /// - /// Gets the tables and views that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetTablesAndViews() => m_Tables.GetValues(); - - /// - /// Preloads all of the metadata for this data source. - /// - public override void Preload() - { - var columns = GetColumnsDataTable(); - var primaryKeys = GetPrimaryKeysDataTable(); + throw new MissingObjectException($"Could not find table or view {tableName}"); + } - PreloadTables(columns, primaryKeys); - PreloadViews(columns); + /// + /// Gets the tables and views that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetTablesAndViews() => m_Tables.GetValues(); - m_SchemaLoaded = true; - } + /// + /// Preloads all of the metadata for this data source. + /// + public override void Preload() + { + var columns = GetColumnsDataTable(); + var primaryKeys = GetPrimaryKeysDataTable(); - /// - /// Preloads metadata for all database tables. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadTables() => PreloadTables(GetColumnsDataTable(), GetPrimaryKeysDataTable()); - - /// - /// Preloads metadata for all database views. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadViews() => PreloadViews(GetColumnsDataTable()); - - /// - /// Resets the metadata cache, clearing out all cached metadata. - /// - public override void Reset() - { - m_DataTableCache.Clear(); - m_Tables.Clear(); - m_TypeTableMap.Clear(); - m_SchemaLoaded = false; - } + PreloadTables(columns, primaryKeys); + PreloadViews(columns); - /// - /// Parse a string and return the database specific representation of the object name. - /// - /// The schema. - /// The name. - /// AccessObjectName. - protected override AccessObjectName ParseObjectName(string? schema, string name) => name; - - /// - /// Determines the database column type from the column type name. - /// - /// Name of the database column type. - /// NOT USED - /// - /// This does not honor registered types. This is only used for the database's hard-coded list of native types. - protected override OleDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) - { - if (Enum.TryParse(typeName, out var result)) - return result; + m_SchemaLoaded = true; + } - return null; - } + /// + /// Preloads metadata for all database tables. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadTables() => PreloadTables(GetColumnsDataTable(), GetPrimaryKeysDataTable()); - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - ColumnMetadataCollection GetColumns(string tableName, DataTable columns, DataTable? primaryKeys) - { - var result = new List>(); - DataTable tableSchema; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) - { - using (var adapter = new OleDbDataAdapter($"SELECT * FROM [{tableName}] WHERE 1=0", con)) - tableSchema = adapter.FillSchema(new DataTable() { Locale = CultureInfo.InvariantCulture }, SchemaType.Source)!; - } + /// + /// Preloads metadata for all database views. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadViews() => PreloadViews(GetColumnsDataTable()); - foreach (DataColumn col in tableSchema.Columns) - { - var name = col.ColumnName; - var isPrimaryKey = false; - var isIdentity = col.AutoIncrement; - OleDbType? type = null; + /// + /// Resets the metadata cache, clearing out all cached metadata. + /// + public override void Reset() + { + m_DataTableCache.Clear(); + m_Tables.Clear(); + m_TypeTableMap.Clear(); + m_SchemaLoaded = false; + } - if (primaryKeys != null) - foreach (DataRow row in primaryKeys.Rows) - { - if (string.Equals(row["TABLE_NAME"].ToString(), tableName, StringComparison.Ordinal) && string.Equals(row["COLUMN_NAME"].ToString(), name, StringComparison.Ordinal)) - { - isPrimaryKey = true; - break; - } - } + /// + /// Parse a string and return the database specific representation of the object name. + /// + /// The schema. + /// The name. + /// AccessObjectName. + protected override AccessObjectName ParseObjectName(string? schema, string name) => name; - bool? isNullable = null; - long? maxLength = null; - int? precision = null; - int? scale = null; - string typeName = ""; - string fullTypeName = ""; //Task-290: Add support for full name + /// + /// Determines the database column type from the column type name. + /// + /// Name of the database column type. + /// NOT USED + /// + /// This does not honor registered types. This is only used for the database's hard-coded list of native types. + protected override OleDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) + { + if (Enum.TryParse(typeName, out var result)) + return result; - foreach (DataRow row in columns.Rows) + return null; + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + ColumnMetadataCollection GetColumns(string tableName, DataTable columns, DataTable? primaryKeys) + { + var result = new List>(); + DataTable tableSchema; + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + using (var adapter = new OleDbDataAdapter($"SELECT * FROM [{tableName}] WHERE 1=0", con)) + tableSchema = adapter.FillSchema(new DataTable() { Locale = CultureInfo.InvariantCulture }, SchemaType.Source)!; + } + + foreach (DataColumn col in tableSchema.Columns) + { + var name = col.ColumnName; + var isPrimaryKey = false; + var isIdentity = col.AutoIncrement; + OleDbType? type = null; + + if (primaryKeys != null) + foreach (DataRow row in primaryKeys.Rows) { if (string.Equals(row["TABLE_NAME"].ToString(), tableName, StringComparison.Ordinal) && string.Equals(row["COLUMN_NAME"].ToString(), name, StringComparison.Ordinal)) { - type = (OleDbType)row["DATA_TYPE"]; - isNullable = (bool)row["IS_NULLABLE"]; - precision = row["NUMERIC_PRECISION"] != DBNull.Value ? (int?)row["NUMERIC_PRECISION"] : null; - scale = row["NUMERIC_SCALE"] != DBNull.Value ? (int?)row["NUMERIC_SCALE"] : null; - maxLength = row["CHARACTER_MAXIMUM_LENGTH"] != DBNull.Value ? (long?)row["CHARACTER_MAXIMUM_LENGTH"] : null; + isPrimaryKey = true; break; } } - Type? clrType = null; - if (type.HasValue) + bool? isNullable = null; + long? maxLength = null; + int? precision = null; + int? scale = null; + string typeName = ""; + string fullTypeName = ""; //Task-290: Add support for full name + + foreach (DataRow row in columns.Rows) + { + if (string.Equals(row["TABLE_NAME"].ToString(), tableName, StringComparison.Ordinal) && string.Equals(row["COLUMN_NAME"].ToString(), name, StringComparison.Ordinal)) { - typeName = type.Value.ToString(); - clrType = ToClrType(type.Value, isNullable ?? true, (int?)maxLength); + type = (OleDbType)row["DATA_TYPE"]; + isNullable = (bool)row["IS_NULLABLE"]; + precision = row["NUMERIC_PRECISION"] != DBNull.Value ? (int?)row["NUMERIC_PRECISION"] : null; + scale = row["NUMERIC_SCALE"] != DBNull.Value ? (int?)row["NUMERIC_SCALE"] : null; + maxLength = row["CHARACTER_MAXIMUM_LENGTH"] != DBNull.Value ? (long?)row["CHARACTER_MAXIMUM_LENGTH"] : null; + break; } + } - result.Add(new ColumnMetadata(name, false, isPrimaryKey, isIdentity, typeName, type ?? OleDbType.Empty, $"[{name}]", isNullable, (int?)maxLength, precision, scale, fullTypeName, clrType)); + Type? clrType = null; + if (type.HasValue) + { + typeName = type.Value.ToString(); + clrType = ToClrType(type.Value, isNullable ?? true, (int?)maxLength); } - return new ColumnMetadataCollection(tableName, result); + result.Add(new ColumnMetadata(name, false, isPrimaryKey, isIdentity, typeName, type ?? OleDbType.Empty, $"[{name}]", isNullable, (int?)maxLength, precision, scale, fullTypeName, clrType)); } - DataTable GetColumnsDataTable() => GetSchemaTable(OleDbSchemaGuid.Columns); + return new ColumnMetadataCollection(tableName, result); + } - DataTable GetPrimaryKeysDataTable() => GetSchemaTable(OleDbSchemaGuid.Primary_Keys); + DataTable GetColumnsDataTable() => GetSchemaTable(OleDbSchemaGuid.Columns); - DataTable GetSchemaTable(Guid oleDbSchemaGuid) - { - return m_DataTableCache.GetOrAdd(oleDbSchemaGuid, sg => - { - using (var connection = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) - { - connection.Open(); - return connection.GetOleDbSchemaTable(sg, null)!; - } - }); - } + DataTable GetPrimaryKeysDataTable() => GetSchemaTable(OleDbSchemaGuid.Primary_Keys); - void PreloadTables(DataTable columnsDataTable, DataTable primaryKeys) + DataTable GetSchemaTable(Guid oleDbSchemaGuid) + { + return m_DataTableCache.GetOrAdd(oleDbSchemaGuid, sg => { using (var connection = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) { connection.Open(); - var dtTables = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null)!; - foreach (DataRow row in dtTables.Rows) - { - if (row["TABLE_TYPE"].ToString() != "TABLE") - continue; + return connection.GetOleDbSchemaTable(sg, null)!; + } + }); + } - var name = row["TABLE_NAME"].ToString()!; - var columns = GetColumns(name, columnsDataTable, primaryKeys); - m_Tables[name] = new TableOrViewMetadata(this, name, true, columns); - } + void PreloadTables(DataTable columnsDataTable, DataTable primaryKeys) + { + using (var connection = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + connection.Open(); + var dtTables = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null)!; + foreach (DataRow row in dtTables.Rows) + { + if (row["TABLE_TYPE"].ToString() != "TABLE") + continue; + + var name = row["TABLE_NAME"].ToString()!; + var columns = GetColumns(name, columnsDataTable, primaryKeys); + m_Tables[name] = new TableOrViewMetadata(this, name, true, columns); } } + } - void PreloadViews(DataTable columnsDataTable) + void PreloadViews(DataTable columnsDataTable) + { + using (var connection = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) { - using (var connection = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + connection.Open(); + var dtViews = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Views, null)!; + foreach (DataRow row in dtViews.Rows) { - connection.Open(); - var dtViews = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Views, null)!; - foreach (DataRow row in dtViews.Rows) - { - var name = row["TABLE_NAME"].ToString()!; - var columns = GetColumns(name, columnsDataTable, null); - m_Tables[name] = new TableOrViewMetadata(this, name, false, columns); - } + var name = row["TABLE_NAME"].ToString()!; + var columns = GetColumns(name, columnsDataTable, null); + m_Tables[name] = new TableOrViewMetadata(this, name, false, columns); } } - - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - /// https://stackoverflow.com/a/54149292/5274 - public override int? MaxParameters => 768; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessObjectName.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessObjectName.cs index db51a67b2..e469d2c23 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessObjectName.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessObjectName.cs @@ -1,127 +1,126 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +/// +/// Represents an object in Access (e.g. table, view, procedure) +/// +public struct AccessObjectName : IEquatable { /// - /// Represents an object in Access (e.g. table, view, procedure) + /// An empty schema/name pair /// - public struct AccessObjectName : IEquatable + public static readonly AccessObjectName Empty; + + /// + /// Initializes a new instance of the struct. + /// + /// The name. + public AccessObjectName(string name) { - /// - /// An empty schema/name pair - /// - public static readonly AccessObjectName Empty; - - /// - /// Initializes a new instance of the struct. - /// - /// The name. - public AccessObjectName(string name) - { - Name = Normalize(name); - } - - /// - /// Gets the name. - /// - /// - /// The name. - /// - public string Name { get; } + Name = Normalize(name); + } + + /// + /// Gets the name. + /// + /// + /// The name. + /// + public string Name { get; } #pragma warning disable CA2225 // Operator overloads have named alternates - /// - /// Perform an implicit conversion from to . - /// - /// The value. - /// - /// The result of the conversion. - /// - public static implicit operator AccessObjectName(string value) => new AccessObjectName(value); + /// + /// Perform an implicit conversion from to . + /// + /// The value. + /// + /// The result of the conversion. + /// + public static implicit operator AccessObjectName(string value) => new AccessObjectName(value); #pragma warning restore CA2225 // Operator overloads have named alternates - /// - /// Implements the operator !=. - /// - /// The left value. - /// The right value. - /// - /// The result of the operator. - /// - /// This is a case-insensitive comparison. - public static bool operator !=(AccessObjectName left, AccessObjectName right) => !(left == right); - - /// - /// Implements the operator ==. - /// - /// The left value. - /// The right value. - /// - /// The result of the operator. - /// - /// This is a case-insensitive comparison. - public static bool operator ==(AccessObjectName left, AccessObjectName right) - { - return string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Determines whether the specified , is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - /// This is a case-insensitive comparison. - public override bool Equals(object? obj) - { - var other = obj as AccessObjectName?; - if (other == null) - return false; - return this == other; - } - - /// - /// Returns true if the two objects are equal. - /// - /// - /// - /// This is a case-insensitive comparison. - public bool Equals(AccessObjectName other) => this == other; - - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - /// This is a case-insensitive comparison. - public override int GetHashCode() => Name.GetHashCode(StringComparison.OrdinalIgnoreCase); - - /// - /// To the quoted string. - /// - /// - public string ToQuotedString() => $"[{Name}]"; - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() => Name; - - [return: NotNullIfNotNull("value")] - private static string? Normalize(string? value) - { - if (value.IsNullOrWhiteSpace()) - return null; - - return value.Replace("[", "", StringComparison.OrdinalIgnoreCase).Replace("]", "", StringComparison.OrdinalIgnoreCase); - } + /// + /// Implements the operator !=. + /// + /// The left value. + /// The right value. + /// + /// The result of the operator. + /// + /// This is a case-insensitive comparison. + public static bool operator !=(AccessObjectName left, AccessObjectName right) => !(left == right); + + /// + /// Implements the operator ==. + /// + /// The left value. + /// The right value. + /// + /// The result of the operator. + /// + /// This is a case-insensitive comparison. + public static bool operator ==(AccessObjectName left, AccessObjectName right) + { + return string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + /// This is a case-insensitive comparison. + public override bool Equals(object? obj) + { + var other = obj as AccessObjectName?; + if (other == null) + return false; + return this == other; + } + + /// + /// Returns true if the two objects are equal. + /// + /// + /// + /// This is a case-insensitive comparison. + public bool Equals(AccessObjectName other) => this == other; + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + /// This is a case-insensitive comparison. + public override int GetHashCode() => Name.GetHashCode(StringComparison.OrdinalIgnoreCase); + + /// + /// To the quoted string. + /// + /// + public string ToQuotedString() => $"[{Name}]"; + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => Name; + + [return: NotNullIfNotNull("value")] + private static string? Normalize(string? value) + { + if (value.IsNullOrWhiteSpace()) + return null; + + return value.Replace("[", "", StringComparison.OrdinalIgnoreCase).Replace("]", "", StringComparison.OrdinalIgnoreCase); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOpenDataSource.cs index 64db52c55..2901ecbe0 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOpenDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOpenDataSource.cs @@ -3,250 +3,234 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +/// +/// Class AccessOpenDataSource. +/// +/// +[UseTrait(typeof(Traits.OpenDataSourceTrait))] +public partial class AccessOpenDataSource : AccessDataSourceBase { - /// - /// Class AccessOpenDataSource. - /// - /// - [UseTrait(typeof(Traits.OpenDataSourceTrait))] - public partial class AccessOpenDataSource : AccessDataSourceBase + internal AccessOpenDataSource(AccessDataSource dataSource, OleDbConnection connection, OleDbTransaction? transaction) : base(new AccessDataSourceSettings(dataSource)) { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - internal AccessOpenDataSource(AccessDataSource dataSource, OleDbConnection connection, OleDbTransaction? transaction) : base(new AccessDataSourceSettings(dataSource)) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - - m_BaseDataSource = dataSource; - m_Connection = connection; - m_Transaction = transaction; - } + m_BaseDataSource = dataSource; + m_Connection = connection; + m_Transaction = transaction; + } - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var currentToken = executionToken as AccessCommandExecutionToken; + if (currentToken == null) + throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var currentToken = executionToken as AccessCommandExecutionToken; - if (currentToken == null) - throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + int? rows = null; + while (currentToken != null) { - int? rows = null; - while (currentToken != null) + OnExecutionStarted(currentToken, startTime, state); + using (var cmd = new OleDbCommand()) { - OnExecutionStarted(currentToken, startTime, state); - using (var cmd = new OleDbCommand()) + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + + currentToken.PopulateCommand(cmd, DefaultCommandTimeout); + + if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) + rows = implementation(cmd); + else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = currentToken.CommandText; - cmd.CommandType = currentToken.CommandType; - foreach (var param in currentToken.Parameters) - cmd.Parameters.Add(param); - - currentToken.ApplyCommandOverrides(cmd); - - if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) - rows = implementation(cmd); - else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) - { - if (currentToken.ForwardResult == null) - throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - - currentToken.ForwardResult(cmd.ExecuteScalar()); - } - else - rows = cmd.ExecuteNonQuery(); - currentToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); + if (currentToken.ForwardResult == null) + throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); + + currentToken.ForwardResult(cmd.ExecuteScalar()); } - currentToken = currentToken.NextCommand; + else + rows = cmd.ExecuteNonQuery(); + currentToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); } - return rows; - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + currentToken = currentToken.NextCommand; } + return rows; } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - try - { - var rows = implementation(m_Connection, m_Transaction); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var currentToken = executionToken as AccessCommandExecutionToken; + if (currentToken == null) + throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var currentToken = executionToken as AccessCommandExecutionToken; - if (currentToken == null) - throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + int? rows = null; + while (currentToken != null) { - int? rows = null; - while (currentToken != null) + OnExecutionStarted(currentToken, startTime, state); + using (var cmd = new OleDbCommand()) { - OnExecutionStarted(currentToken, startTime, state); - using (var cmd = new OleDbCommand()) + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + currentToken.PopulateCommand(cmd, DefaultCommandTimeout); + + if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) + rows = await implementation(cmd).ConfigureAwait(false); + else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = currentToken.CommandText; - cmd.CommandType = currentToken.CommandType; - foreach (var param in currentToken.Parameters) - cmd.Parameters.Add(param); - - currentToken.ApplyCommandOverrides(cmd); - - if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) - rows = await implementation(cmd).ConfigureAwait(false); - else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) - { - if (currentToken.ForwardResult == null) - throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - - currentToken.ForwardResult(await cmd.ExecuteScalarAsync().ConfigureAwait(false)); - } - else - rows = await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); + if (currentToken.ForwardResult == null) + throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); + + currentToken.ForwardResult(await cmd.ExecuteScalarAsync().ConfigureAwait(false)); } - currentToken = currentToken.NextCommand; + else + rows = await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); } - return rows; + currentToken = currentToken.NextCommand; } - catch (Exception ex) + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert AccessException into a OperationCanceledException { - if (cancellationToken.IsCancellationRequested) //convert AccessException into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; + } + else + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - private partial AccessOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) - { - if (userValue != null) - UserValue = userValue; - if (additionalRules != null) - AuditRules = new AuditRuleCollection(AuditRules, additionalRules); + private partial AccessOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) + { + if (userValue != null) + UserValue = userValue; + if (additionalRules != null) + AuditRules = new AuditRuleCollection(AuditRules, additionalRules); - return this; - } + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOperationExecutionToken.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOperationExecutionToken.cs index 54f1e4acb..fdd330360 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOperationExecutionToken.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessOperationExecutionToken.cs @@ -2,26 +2,20 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Access -{ +namespace Tortuga.Chain.Access; +/// +/// Class AccessExecutionToken. +/// +public sealed class AccessOperationExecutionToken : OperationExecutionToken +{ /// - /// Class AccessExecutionToken. + /// Initializes a new instance of the class. /// - public sealed class AccessOperationExecutionToken : OperationExecutionToken + /// The data source. + /// Name of the operation. This is used for logging. + public AccessOperationExecutionToken(IOperationDataSource dataSource, string operationName) + : base(dataSource, operationName) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. This is used for logging. - public AccessOperationExecutionToken(IOperationDataSource dataSource, string operationName) - : base(dataSource, operationName) - { - - } - - - } } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessTransactionalDataSource.cs index b1863a439..761514367 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessTransactionalDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/AccessTransactionalDataSource.cs @@ -3,303 +3,285 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +/// +/// Class AccessTransactionalDataSource +/// +[UseTrait(typeof(Traits.TransactionalDataSourceTrait))] +public partial class AccessTransactionalDataSource : AccessDataSourceBase { /// - /// Class AccessTransactionalDataSource + /// Initializes a new instance of the class. /// - [UseTrait(typeof(Traits.TransactionalDataSourceTrait))] - public partial class AccessTransactionalDataSource : AccessDataSourceBase + /// The data source. + /// The isolation level. + /// if set to true [forward events]. + public AccessTransactionalDataSource(AccessDataSource dataSource, IsolationLevel? isolationLevel, bool forwardEvents) : base(new AccessDataSourceSettings(dataSource, forwardEvents)) { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + Name = dataSource.Name; - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The isolation level. - /// if set to true [forward events]. - public AccessTransactionalDataSource(AccessDataSource dataSource, IsolationLevel? isolationLevel, bool forwardEvents) : base(new AccessDataSourceSettings(dataSource, forwardEvents)) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - - Name = dataSource.Name; - - m_BaseDataSource = dataSource; - m_Connection = dataSource.CreateConnection(); + m_BaseDataSource = dataSource; + m_Connection = dataSource.CreateConnection(); - if (isolationLevel == null) - m_Transaction = m_Connection.BeginTransaction(); - else - m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value); + if (isolationLevel == null) + m_Transaction = m_Connection.BeginTransaction(); + else + m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value); - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// if set to true [forward events]. - /// The connection. - /// The transaction. - /// - /// - internal AccessTransactionalDataSource(AccessDataSource dataSource, bool forwardEvents, OleDbConnection connection, OleDbTransaction transaction) : base(new AccessDataSourceSettings(dataSource, forwardEvents)) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (transaction == null) - throw new ArgumentNullException(nameof(transaction), $"{nameof(transaction)} is null."); + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } - Name = dataSource.Name; + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// if set to true [forward events]. + /// The connection. + /// The transaction. + /// + /// + internal AccessTransactionalDataSource(AccessDataSource dataSource, bool forwardEvents, OleDbConnection connection, OleDbTransaction transaction) : base(new AccessDataSourceSettings(dataSource, forwardEvents)) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (transaction == null) + throw new ArgumentNullException(nameof(transaction), $"{nameof(transaction)} is null."); - m_BaseDataSource = dataSource; - m_Connection = connection; - m_Transaction = transaction; + Name = dataSource.Name; - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } + m_BaseDataSource = dataSource; + m_Connection = connection; + m_Transaction = transaction; - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } - /// - /// Executes the specified execution token. - /// - /// The execution token. - /// The implementation. - /// The state. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + /// + /// Executes the specified execution token. + /// + /// The execution token. + /// The implementation. + /// The state. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var currentToken = executionToken as AccessCommandExecutionToken; + if (currentToken == null) + throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var currentToken = executionToken as AccessCommandExecutionToken; - if (currentToken == null) - throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + int? rows = null; + while (currentToken != null) { - int? rows = null; - while (currentToken != null) + OnExecutionStarted(currentToken, startTime, state); + using (var cmd = new OleDbCommand()) { - OnExecutionStarted(currentToken, startTime, state); - using (var cmd = new OleDbCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = currentToken.CommandText; - cmd.CommandType = currentToken.CommandType; - foreach (var param in currentToken.Parameters) - cmd.Parameters.Add(param); + currentToken.PopulateCommand(cmd, DefaultCommandTimeout); - currentToken.ApplyCommandOverrides(cmd); - - if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) - rows = implementation(cmd); - else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) - { - if (currentToken.ForwardResult == null) - throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); + if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) + rows = implementation(cmd); + else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) + { + if (currentToken.ForwardResult == null) + throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - currentToken.ForwardResult(cmd.ExecuteScalar()); - } - else - rows = cmd.ExecuteNonQuery(); - currentToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); + currentToken.ForwardResult(cmd.ExecuteScalar()); } - currentToken = currentToken.NextCommand; + else + rows = cmd.ExecuteNonQuery(); + currentToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); } - return rows; - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + currentToken = currentToken.NextCommand; } + return rows; } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - try - { - var rows = implementation(m_Connection, m_Transaction); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var currentToken = executionToken as AccessCommandExecutionToken; - if (currentToken == null) - throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - try + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var currentToken = executionToken as AccessCommandExecutionToken; + if (currentToken == null) + throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + int? rows = null; + while (currentToken != null) { - int? rows = null; - while (currentToken != null) + OnExecutionStarted(currentToken, startTime, state); + using (var cmd = new OleDbCommand()) { - OnExecutionStarted(currentToken, startTime, state); - using (var cmd = new OleDbCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = currentToken.CommandText; - cmd.CommandType = currentToken.CommandType; - foreach (var param in currentToken.Parameters) - cmd.Parameters.Add(param); - - currentToken.ApplyCommandOverrides(cmd); + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + currentToken.PopulateCommand(cmd, DefaultCommandTimeout); - if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) - rows = await implementation(cmd).ConfigureAwait(false); - else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) - { - if (currentToken.ForwardResult == null) - throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); + if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) + rows = await implementation(cmd).ConfigureAwait(false); + else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) + { + if (currentToken.ForwardResult == null) + throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - currentToken.ForwardResult(await cmd.ExecuteScalarAsync().ConfigureAwait(false)); - } - else - rows = await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); + currentToken.ForwardResult(await cmd.ExecuteScalarAsync().ConfigureAwait(false)); } - currentToken = currentToken.NextCommand; + else + rows = await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); } - return rows; + currentToken = currentToken.NextCommand; } - catch (Exception ex) + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert AccessException into a OperationCanceledException { - if (cancellationToken.IsCancellationRequested) //convert AccessException into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; + } + else + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert AccessException into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert AccessException into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteObject`1.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteObject`1.cs index 70eada90b..b7b0e9a9b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteObject`1.cs @@ -3,53 +3,52 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Command object that represents a delete operation. +/// +internal sealed class AccessDeleteObject : AccessObjectCommand + where TArgument : class { + readonly DeleteOptions m_Options; + /// - /// Command object that represents a delete operation. + /// Initializes a new instance of the class. /// - internal sealed class AccessDeleteObject : AccessObjectCommand - where TArgument : class + /// The data source. + /// The table. + /// The argument value. + /// The options. + public AccessDeleteObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, DeleteOptions options) + : base(dataSource, tableName, argumentValue) { - readonly DeleteOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The table. - /// The argument value. - /// The options. - public AccessDeleteObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, DeleteOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); - - var sql = new StringBuilder(); - sql.Append("DELETE FROM " + Table.Name.ToQuotedString()); - sqlBuilder.BuildWhereClause(sql, " WHERE ", null); - sql.Append(";"); - - return new AccessCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); - } + m_Options = options; + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); + + var sql = new StringBuilder(); + sql.Append("DELETE FROM " + Table.Name.ToQuotedString()); + sqlBuilder.BuildWhereClause(sql, " WHERE ", null); + sql.Append(";"); + + return new AccessCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(DataSource)).CheckDeleteRowCount(m_Options); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteSet.cs index de5c4b03f..62a2e7474 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessDeleteSet.cs @@ -5,164 +5,163 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Class AccessDeleteSet. +/// +internal sealed class AccessDeleteSet : MultipleRowDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly int? m_ExpectedRowCount; + readonly FilterOptions m_FilterOptions; + readonly object? m_FilterValue; + readonly DeleteOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly TableOrViewMetadata m_Table; + readonly string? m_WhereClause; + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public AccessDeleteSet(AccessDataSourceBase dataSource, AccessObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) + { + if (options.HasFlag(DeleteOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_Parameters = parameters; + m_Options = options; + m_ExpectedRowCount = expectedRowCount; + } + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The where clause. + /// The argument value. + public AccessDeleteSet(AccessDataSourceBase dataSource, AccessObjectName tableName, string whereClause, object? argumentValue) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + } + /// - /// Class AccessDeleteSet. + /// Initializes a new instance of the class. /// - internal sealed class AccessDeleteSet : MultipleRowDbCommandBuilder + /// The data source. + /// Name of the table. + /// The filter value. + /// The options. + public AccessDeleteSet(AccessDataSourceBase dataSource, AccessObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly FilterOptions m_FilterOptions; - readonly object? m_FilterValue; - readonly IEnumerable? m_Parameters; - readonly TableOrViewMetadata m_Table; - readonly string? m_WhereClause; - readonly DeleteOptions m_Options; - readonly int? m_ExpectedRowCount; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public AccessDeleteSet(AccessDataSourceBase dataSource, AccessObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + } + + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + List parameters; + var sql = new StringBuilder(); + + sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); + if (m_FilterValue != null) { - if (options.HasFlag(DeleteOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_Parameters = parameters; - m_Options = options; - m_ExpectedRowCount = expectedRowCount; + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + parameters = sqlBuilder.GetParameters(DataSource); } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The argument value. - public AccessDeleteSet(AccessDataSourceBase dataSource, AccessObjectName tableName, string whereClause, object? argumentValue) : base(dataSource) + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; + sql.Append(" WHERE " + m_WhereClause); + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters(DataSource)); } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The filter value. - /// The options. - public AccessDeleteSet(AccessDataSourceBase dataSource, AccessObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) + else { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; + parameters = sqlBuilder.GetParameters(DataSource); } + sql.Append(";"); + if (m_Parameters != null) + parameters.AddRange(m_Parameters); + + var deleteCommand = new AccessCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); + + var desiredColumns = materializer.DesiredColumns(); + if (desiredColumns == Materializer.NoColumns) + return deleteCommand; + + var result = PrepareRead(desiredColumns); + result.NextCommand = deleteCommand; + return result; + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - public override CommandExecutionToken Prepare(Materializer materializer) + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + AccessCommandExecutionToken PrepareRead(IReadOnlyList desiredColumns) + { + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + List parameters; + var sql = new StringBuilder(); + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + sql.Append(" FROM " + m_Table.Name.ToQuotedString()); + if (m_FilterValue != null) { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - List parameters; - var sql = new StringBuilder(); - - sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } - sql.Append(";"); - if (m_Parameters != null) - parameters.AddRange(m_Parameters); - - var deleteCommand = new AccessCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); - - var desiredColumns = materializer.DesiredColumns(); - if (desiredColumns == Materializer.NoColumns) - return deleteCommand; - - var result = PrepareRead(desiredColumns); - result.NextCommand = deleteCommand; - return result; + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + parameters = sqlBuilder.GetParameters(DataSource); } - - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - AccessCommandExecutionToken PrepareRead(IReadOnlyList desiredColumns) + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) { - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - List parameters; - var sql = new StringBuilder(); - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - sql.Append(" FROM " + m_Table.Name.ToQuotedString()); - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } - sql.Append(";"); - - if (m_Parameters != null) - parameters.AddRange(m_Parameters.Select(p => p.Clone())); - - return new AccessCommandExecutionToken(DataSource, "Query after deleting " + m_Table.Name, sql.ToString(), parameters); + sql.Append(" WHERE " + m_WhereClause); + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters(DataSource)); } + else + { + parameters = sqlBuilder.GetParameters(DataSource); + } + sql.Append(";"); + + if (m_Parameters != null) + parameters.AddRange(m_Parameters.Select(p => p.Clone())); + + return new AccessCommandExecutionToken(DataSource, "Query after deleting " + m_Table.Name, sql.ToString(), parameters); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertObject`1.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertObject`1.cs index 649cbc992..6c7dbf2b9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertObject`1.cs @@ -3,98 +3,97 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Class that represents a Access Insert. +/// +internal sealed class AccessInsertObject : AccessObjectCommand + where TArgument : class { + readonly InsertOptions m_Options; + /// - /// Class that represents a Access Insert. + /// Initializes a new instance of class. /// - internal sealed class AccessInsertObject : AccessObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public AccessInsertObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, InsertOptions options) + : base(dataSource, tableName, argumentValue) { - readonly InsertOptions m_Options; - - /// - /// Initializes a new instance of class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public AccessInsertObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, InsertOptions options) - : base(dataSource, tableName, argumentValue) + m_Options = options; + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var desiredColumns = materializer.DesiredColumns(); + var identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); + + var sql = new StringBuilder(); + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToQuotedString()} (", null, ")", identityInsert); + sqlBuilder.BuildValuesClause(sql, " VALUES (", ")", identityInsert); + sql.Append(";"); + + var result = new AccessCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(DataSource)); + if (desiredColumns == Materializer.AutoSelectDesiredColumns) { - m_Options = options; + result.ExecutionMode = AccessCommandExecutionMode.NonQuery; + result.NextCommand = new AccessCommandExecutionToken(DataSource, "Fetch autonumber", "SELECT @@IDENTITY", new List()); } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) + else if (desiredColumns.Count > 0) { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var desiredColumns = materializer.DesiredColumns(); - var identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); - - var sql = new StringBuilder(); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToQuotedString()} (", null, ")", identityInsert); - sqlBuilder.BuildValuesClause(sql, " VALUES (", ")", identityInsert); - sql.Append(";"); - - var result = new AccessCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); - if (desiredColumns == Materializer.AutoSelectDesiredColumns) - { - result.ExecutionMode = AccessCommandExecutionMode.NonQuery; - result.NextCommand = new AccessCommandExecutionToken(DataSource, "Fetch autonumber", "SELECT @@IDENTITY", new List()); - } - else if (desiredColumns.Count > 0) - { - result.ExecutionMode = AccessCommandExecutionMode.NonQuery; - result.NextCommand = new AccessCommandExecutionToken(DataSource, "Fetch autonumber", "SELECT @@IDENTITY", new List()); - result.NextCommand.ExecutionMode = AccessCommandExecutionMode.ExecuteScalarAndForward; - result.NextCommand.ForwardResult = value => { result.NextCommand.NextCommand = PrepareNext(desiredColumns, value); }; - } - - return result; + result.ExecutionMode = AccessCommandExecutionMode.NonQuery; + result.NextCommand = new AccessCommandExecutionToken(DataSource, "Fetch autonumber", "SELECT @@IDENTITY", new List()); + result.NextCommand.ExecutionMode = AccessCommandExecutionMode.ExecuteScalarAndForward; + result.NextCommand.ForwardResult = value => { result.NextCommand.NextCommand = PrepareNext(desiredColumns, value); }; } - AccessCommandExecutionToken PrepareNext(IReadOnlyList desiredColumns, object? previousValue) - { - var primaryKeys = Table.PrimaryKeyColumns; - if (primaryKeys.Count != 1) - throw new MappingException($"Insert operation cannot return any values for {Table.Name} because it doesn't have a single primary key."); + return result; + } + + AccessCommandExecutionToken PrepareNext(IReadOnlyList desiredColumns, object? previousValue) + { + var primaryKeys = Table.PrimaryKeyColumns; + if (primaryKeys.Count != 1) + throw new MappingException($"Insert operation cannot return any values for {Table.Name} because it doesn't have a single primary key."); - var columnMetadata = primaryKeys.Single(); - var where = columnMetadata.SqlName + " = " + columnMetadata.SqlVariableName; + var columnMetadata = primaryKeys.Single(); + var where = columnMetadata.SqlName + " = " + columnMetadata.SqlVariableName; - var parameters = new List(); + var parameters = new List(); - var param = new OleDbParameter(columnMetadata.SqlVariableName, previousValue); - if (columnMetadata.DbType.HasValue) - param.OleDbType = columnMetadata.DbType.Value; - parameters.Add(param); + var param = new OleDbParameter(columnMetadata.SqlVariableName, previousValue); + if (columnMetadata.DbType.HasValue) + param.OleDbType = columnMetadata.DbType.Value; + parameters.Add(param); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(desiredColumns); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(desiredColumns); - var sql = new StringBuilder(); - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - sql.Append(" FROM " + Table.Name.ToQuotedString()); - sql.Append(" WHERE " + where); - sql.Append(";"); + var sql = new StringBuilder(); + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + sql.Append(" FROM " + Table.Name.ToQuotedString()); + sql.Append(" WHERE " + where); + sql.Append(";"); - return new AccessCommandExecutionToken(DataSource, "Select after insert into " + Table.Name, sql.ToString(), parameters); - } + return new AccessCommandExecutionToken(DataSource, "Select after insert into " + Table.Name, sql.ToString(), parameters); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertOrUpdateObject`1.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertOrUpdateObject`1.cs deleted file mode 100644 index 042e1f35b..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessInsertOrUpdateObject`1.cs +++ /dev/null @@ -1,38 +0,0 @@ -//using System; -//using System.Data.OleDb; -//using System.Linq; -//using System.Text; -//using Tortuga.Chain.Core; -//using Tortuga.Chain.Materializers; - - -//namespace Tortuga.Chain.Access.CommandBuilders -//{ -// /// -// /// Class AccessInsertOrUpdateObject -// /// -// internal sealed class AccessInsertOrUpdateObject : AccessObjectCommand -// where TArgument : class -// { -// readonly UpsertOptions m_Options; - -// /// -// /// Initializes a new instance of the class. -// /// -// /// -// /// -// /// -// /// -// public AccessInsertOrUpdateObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, UpsertOptions options) -// : base(dataSource, tableName, argumentValue) -// { -// m_Options = options; -// } - -// public override CommandExecutionToken Prepare(Materializer materializer) -// { -// throw new NotImplementedException(); -// } - -// } -//} diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessObjectCommand`1.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessObjectCommand`1.cs index 1743a8b4d..0a3d2274e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessObjectCommand`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessObjectCommand`1.cs @@ -2,35 +2,34 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Base class that describes a Access database command. +/// +internal abstract class AccessObjectCommand : ObjectDbCommandBuilder + where TArgument : class { /// - /// Base class that describes a Access database command. + /// Initializes a new instance of the class /// - internal abstract class AccessObjectCommand : ObjectDbCommandBuilder - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + protected AccessObjectCommand(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue) + : base(dataSource, argumentValue) { - /// - /// Initializes a new instance of the class - /// - /// The data source. - /// Name of the table. - /// The argument value. - protected AccessObjectCommand(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue) - : base(dataSource, argumentValue) - { - Table = ((AccessDataSourceBase)DataSource).DatabaseMetadata.GetTableOrView(tableName); - } + Table = ((AccessDataSourceBase)DataSource).DatabaseMetadata.GetTableOrView(tableName); + } - /// - /// Gets the table metadata. - /// - public TableOrViewMetadata Table { get; } + /// + /// Gets the table metadata. + /// + public TableOrViewMetadata Table { get; } - /// - /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. - /// - /// - protected override TableOrViewMetadata OnGetTable() => Table; - } -} + /// + /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. + /// + /// + protected override TableOrViewMetadata OnGetTable() => Table; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessSqlCall.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessSqlCall.cs index d148f4a22..539e9f8c6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessSqlCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessSqlCall.cs @@ -5,62 +5,61 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Class that represents an operation based on a raw SQL statement. +/// +internal sealed class AccessSqlCall : MultipleTableDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly string m_SqlStatement; + /// - /// Class that represents an operation based on a raw SQL statement. + /// Creates a new instance of /// - internal sealed class AccessSqlCall : MultipleTableDbCommandBuilder + /// The data source. + /// The SQL statement. + /// The argument value. + /// SQL statement is null or empty.;sqlStatement + public AccessSqlCall(AccessDataSourceBase dataSource, string sqlStatement, object? argumentValue) : + base(dataSource) { - readonly object? m_ArgumentValue; - readonly string m_SqlStatement; + if (string.IsNullOrEmpty(sqlStatement)) + throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); - /// - /// Creates a new instance of - /// - /// The data source. - /// The SQL statement. - /// The argument value. - /// SQL statement is null or empty.;sqlStatement - public AccessSqlCall(AccessDataSourceBase dataSource, string sqlStatement, object? argumentValue) : - base(dataSource) - { - if (string.IsNullOrEmpty(sqlStatement)) - throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); - - m_SqlStatement = sqlStatement; - m_ArgumentValue = argumentValue; - } + m_SqlStatement = sqlStatement; + m_ArgumentValue = argumentValue; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - return new AccessCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + return new AccessCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => null; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => null; - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessTableOrView.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessTableOrView.cs index 4717e8774..e376f73fa 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessTableOrView.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessTableOrView.cs @@ -5,260 +5,270 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// AccessTableOrView supports queries against tables and views. +/// +internal sealed class AccessTableOrView : TableDbCommandBuilder + where TObject : class { + readonly TableOrViewMetadata m_Table; + object? m_ArgumentValue; + FilterOptions m_FilterOptions; + object? m_FilterValue; + AccessLimitOption m_LimitOptions; + string? m_SelectClause; + IEnumerable m_SortExpressions = Enumerable.Empty(); + int? m_Take; + string? m_WhereClause; + /// - /// AccessTableOrView supports queries against tables and views. + /// Initializes a new instance of the class. /// - internal sealed class AccessTableOrView : TableDbCommandBuilder - where TObject : class + /// The data source. + /// Name of the table or view. + /// The filter value. + /// The filter options. + public AccessTableOrView(AccessDataSourceBase dataSource, AccessObjectName tableOrViewName, object filterValue, FilterOptions filterOptions) : + base(dataSource) { - readonly TableOrViewMetadata m_Table; - object? m_ArgumentValue; - FilterOptions m_FilterOptions; - object? m_FilterValue; - AccessLimitOption m_LimitOptions; - string? m_SelectClause; - IEnumerable m_SortExpressions = Enumerable.Empty(); - int? m_Take; - string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The filter value. - /// The filter options. - public AccessTableOrView(AccessDataSourceBase dataSource, AccessObjectName tableOrViewName, object filterValue, FilterOptions filterOptions) : - base(dataSource) - { - m_FilterValue = filterValue; - m_Table = ((AccessDataSourceBase)DataSource).DatabaseMetadata.GetTableOrView(tableOrViewName); - m_FilterOptions = filterOptions; - } + m_FilterValue = filterValue; + m_Table = ((AccessDataSourceBase)DataSource).DatabaseMetadata.GetTableOrView(tableOrViewName); + m_FilterOptions = filterOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - public AccessTableOrView(AccessDataSourceBase dataSource, AccessObjectName tableOrViewName, string? whereClause, object? argumentValue) : - base(dataSource) - { - m_ArgumentValue = argumentValue; - m_WhereClause = whereClause; - m_Table = ((AccessDataSourceBase)DataSource).DatabaseMetadata.GetTableOrView(tableOrViewName); - } + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public AccessTableOrView(AccessDataSourceBase dataSource, AccessObjectName tableOrViewName, string? whereClause, object? argumentValue) : + base(dataSource) + { + m_ArgumentValue = argumentValue; + m_WhereClause = whereClause; + m_Table = ((AccessDataSourceBase)DataSource).DatabaseMetadata.GetTableOrView(tableOrViewName); + } - /// - /// Gets the default limit option. - /// - /// - /// The default limit options. - /// - /// - /// For most data sources, this will be LimitOptions.Rows. - /// - protected override LimitOptions DefaultLimitOption => LimitOptions.RowsWithTies; - - /// - /// Returns the row count using a SELECT COUNT_BIG(*) style query. - /// - /// - public override ILink AsCount() - { - m_SelectClause = "COUNT(*)"; - return ToInt64(); - } + /// + /// Gets the default limit option. + /// + /// + /// The default limit options. + /// + /// + /// For most data sources, this will be LimitOptions.Rows. + /// + protected override LimitOptions DefaultLimitOption => LimitOptions.RowsWithTies; - /// - /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). - /// - public override ILink AsCount(string columnName, bool distinct = false) - { - if (distinct) - throw new NotSupportedException("Access does not support distinct counts."); + /// + /// Returns the row count using a SELECT COUNT_BIG(*) style query. + /// + /// + public override ILink AsCount() + { + m_SelectClause = "COUNT(*)"; + return ToInt64(); + } - var column = m_Table.Columns[columnName]; - m_SelectClause = $"COUNT({column.QuotedSqlName})"; + /// + /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). + /// + public override ILink AsCount(string columnName, bool distinct = false) + { + if (distinct) + throw new NotSupportedException("Access does not support distinct counts."); - return ToInt64(); - } + var column = m_Table.Columns[columnName]; + m_SelectClause = $"COUNT({column.QuotedSqlName})"; - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - //Support check - if (!Enum.IsDefined(typeof(AccessLimitOption), m_LimitOptions)) - throw new NotSupportedException($"Access does not support limit option {(LimitOptions)m_LimitOptions}"); - - //Validation - - if (m_Take <= 0) - throw new InvalidOperationException($"Cannot take {m_Take} rows"); - - //SQL Generation - List parameters; - var sql = new StringBuilder(); - - string? topClause = null; - switch (m_LimitOptions) - { - case AccessLimitOption.RowsWithTies: - topClause = $"TOP {m_Take} "; - break; - } - - if (m_SelectClause != null) - sql.Append($"SELECT {topClause} {m_SelectClause} "); - else - sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); - - sql.Append(" FROM " + m_Table.Name.ToQuotedString()); - - if (m_FilterValue != null) - { - sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE (" + m_WhereClause + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); - parameters = sqlBuilder.GetParameters(); - } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + return ToInt64(); + } - sql.Append(";"); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - return new AccessCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); - } + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + //Support check + if (!Enum.IsDefined(typeof(AccessLimitOption), m_LimitOptions)) + throw new NotSupportedException($"Access does not support limit option {(LimitOptions)m_LimitOptions}"); + + //Validation + + if (m_Take <= 0) + throw new InvalidOperationException($"Cannot take {m_Take} rows"); + + //SQL Generation + List parameters; + var sql = new StringBuilder(); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<OleDbCommand, OleDbParameter, AccessLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + string? topClause = null; + switch (m_LimitOptions) { - m_FilterValue = filterValue; - m_WhereClause = null; - m_ArgumentValue = null; - m_FilterOptions = filterOptions; - return this; + case AccessLimitOption.RowsWithTies: + topClause = $"TOP {m_Take} "; + break; } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + if (m_SelectClause != null) + sql.Append($"SELECT {topClause} {m_SelectClause} "); + else + sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); + + sql.Append(" FROM " + m_Table.Name.ToQuotedString()); + + if (m_FilterValue != null) { - m_FilterValue = null; - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - return this; + sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); + + parameters = sqlBuilder.GetParameters(DataSource); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE (" + m_WhereClause + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters(DataSource)); + } + else { - m_SortExpressions = sortExpressions ?? throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); - return this; + sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); + parameters = sqlBuilder.GetParameters(DataSource); } - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, AccessLimitOption limitOptions, int? seed) + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any()) { - if (skip.HasValue) - throw new NotSupportedException("Row skipping isn't supported by Access"); - if (seed.HasValue) - throw new NotSupportedException("Seed values are not supported by Access"); - - m_Take = take; - m_LimitOptions = limitOptions; - return this; + if (m_Table.HasPrimaryKey) + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_Table.PrimaryKeyColumns.Select(x => new SortExpression(x.SqlName)), null); + else if (StrictMode) + throw new InvalidOperationException("Limits were requested, but no primary keys were detected. Use WithSorting to supply a sort order or disable strict mode."); } - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + else { - if (skip.HasValue) - throw new NotSupportedException("Row skipping isn't supported by Access"); - if (seed.HasValue) - throw new NotSupportedException("Seed values are not supported by Access"); - - m_Take = take; - m_LimitOptions = (AccessLimitOption)limitOptions; - return this; + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); } + + sql.Append(";"); + + return new AccessCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// TableDbCommandBuilder<OleDbCommand, OleDbParameter, AccessLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_FilterValue = filterValue; + m_WhereClause = null; + m_ArgumentValue = null; + m_FilterOptions = filterOptions; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + { + m_FilterValue = null; + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, AccessLimitOption limitOptions, int? seed) + { + if (skip.HasValue) + throw new NotSupportedException("Row skipping isn't supported by Access"); + if (seed.HasValue) + throw new NotSupportedException("Seed values are not supported by Access"); + + m_Take = take; + m_LimitOptions = limitOptions; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + { + if (skip.HasValue) + throw new NotSupportedException("Row skipping isn't supported by Access"); + if (seed.HasValue) + throw new NotSupportedException("Seed values are not supported by Access"); + + m_Take = take; + m_LimitOptions = (AccessLimitOption)limitOptions; + return this; + } + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + m_SortExpressions = sortExpressions ?? throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateObject`1.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateObject`1.cs index 258f42d7e..aa07921bb 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateObject`1.cs @@ -3,90 +3,89 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Command object that represents an update operation. +/// +internal sealed class AccessUpdateObject : AccessObjectCommand + where TArgument : class { + readonly UpdateOptions m_Options; + /// - /// Command object that represents an update operation. + /// Initializes a new instance of the class. /// - internal sealed class AccessUpdateObject : AccessObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public AccessUpdateObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, UpdateOptions options) + : base(dataSource, tableName, argumentValue) { - readonly UpdateOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public AccessUpdateObject(AccessDataSourceBase dataSource, AccessObjectName tableName, TArgument argumentValue, UpdateOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (!Table.IsTable) - throw new MappingException($"Cannot perform an update operation on the view {Table.Name}."); + if (!Table.IsTable) + throw new MappingException($"Cannot perform an update operation on the view {Table.Name}."); - if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) - throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); + if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) + throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var sql = new StringBuilder($"UPDATE {Table.Name.ToQuotedString()}"); - sqlBuilder.BuildSetClause(sql, " SET ", null, null); - sqlBuilder.BuildWhereClause(sql, " WHERE ", null); - sql.Append(";"); + var sql = new StringBuilder($"UPDATE {Table.Name.ToQuotedString()}"); + sqlBuilder.BuildSetClause(sql, " SET ", null, null); + sqlBuilder.BuildWhereClause(sql, " WHERE ", null); + sql.Append(";"); - var updateCommand = new AccessCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParametersKeysLast()).CheckUpdateRowCount(m_Options); - updateCommand.ExecutionMode = AccessCommandExecutionMode.NonQuery; + var updateCommand = new AccessCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParametersKeysLast()).CheckUpdateRowCount(m_Options); + updateCommand.ExecutionMode = AccessCommandExecutionMode.NonQuery; - if (desiredColumns == Materializer.NoColumns) - return updateCommand; + if (desiredColumns == Materializer.NoColumns) + return updateCommand; - if (m_Options.HasFlag(UpdateOptions.ReturnOldValues)) - { - var result = PrepareRead(desiredColumns, "before"); - result.NextCommand = updateCommand; - return result; - } - else - { - updateCommand.NextCommand = PrepareRead(desiredColumns, "after"); - return updateCommand; - } + if (m_Options.HasFlag(UpdateOptions.ReturnOldValues)) + { + var result = PrepareRead(desiredColumns, "before"); + result.NextCommand = updateCommand; + return result; } - - AccessCommandExecutionToken PrepareRead(IReadOnlyList desiredColumns, string label) + else { - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, false); + updateCommand.NextCommand = PrepareRead(desiredColumns, "after"); + return updateCommand; + } + } + + AccessCommandExecutionToken PrepareRead(IReadOnlyList desiredColumns, string label) + { + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, false); - var sql = new StringBuilder(); - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - sql.Append(" FROM " + Table.Name.ToQuotedString()); - sqlBuilder.BuildWhereClause(sql, " WHERE ", null); - sql.Append(";"); + var sql = new StringBuilder(); + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + sql.Append(" FROM " + Table.Name.ToQuotedString()); + sqlBuilder.BuildWhereClause(sql, " WHERE ", null); + sql.Append(";"); - return new AccessCommandExecutionToken(DataSource, $"Query {label} updating " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); - } + return new AccessCommandExecutionToken(DataSource, $"Query {label} updating " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(DataSource)); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateSet.cs index 63206c2f3..7a0c38d8c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/CommandBuilders/AccessUpdateSet.cs @@ -5,264 +5,263 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Access.CommandBuilders +namespace Tortuga.Chain.Access.CommandBuilders; + +/// +/// Class AccessUpdateSet. +/// +internal sealed class AccessUpdateSet : UpdateSetDbCommandBuilder { + readonly int? m_ExpectedRowCount; + readonly object? m_NewValues; + readonly UpdateOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly TableOrViewMetadata m_Table; + readonly object? m_UpdateArgumentValue; + readonly string? m_UpdateExpression; + FilterOptions m_FilterOptions; + object? m_FilterValue; + object? m_WhereArgumentValue; + string? m_WhereClause; + /// - /// Class AccessUpdateSet. + /// Initializes a new instance of the class. /// - internal sealed class AccessUpdateSet : UpdateSetDbCommandBuilder + /// The data source. + /// Name of the table. + /// The new values. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public AccessUpdateSet(AccessDataSourceBase dataSource, AccessObjectName tableName, object? newValues, string whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) { - readonly int? m_ExpectedRowCount; - readonly object? m_NewValues; - readonly UpdateOptions m_Options; - readonly IEnumerable? m_Parameters; - readonly TableOrViewMetadata m_Table; - readonly object? m_UpdateArgumentValue; - readonly string? m_UpdateExpression; - FilterOptions m_FilterOptions; - object? m_FilterValue; - object? m_WhereArgumentValue; - string? m_WhereClause; + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public AccessUpdateSet(AccessDataSourceBase dataSource, AccessObjectName tableName, object? newValues, string whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_WhereClause = whereClause; + m_ExpectedRowCount = expectedRowCount; + m_Options = options; + m_Parameters = parameters; + } - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_WhereClause = whereClause; - m_ExpectedRowCount = expectedRowCount; - m_Options = options; - m_Parameters = parameters; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The new values. + /// The options. + /// Cannot use Key attributes with this operation. + public AccessUpdateSet(AccessDataSourceBase dataSource, AccessObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The options. - /// Cannot use Key attributes with this operation. - public AccessUpdateSet(AccessDataSourceBase dataSource, AccessObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_Options = options; + } - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_Options = options; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The update expression. + /// The update argument value. + /// The options. + /// Cannot use Key attributes with this operation. + public AccessUpdateSet(AccessDataSourceBase dataSource, AccessObjectName tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The update expression. - /// The update argument value. - /// The options. - /// Cannot use Key attributes with this operation. - public AccessUpdateSet(AccessDataSourceBase dataSource, AccessObjectName tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_UpdateExpression = updateExpression; + m_Options = options; + m_UpdateArgumentValue = updateArgumentValue; + } - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_UpdateExpression = updateExpression; - m_Options = options; - m_UpdateArgumentValue = updateArgumentValue; - } + /// + /// Applies this command to all rows. + /// + /// + public override UpdateSetDbCommandBuilder All() + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); - /// - /// Applies this command to all rows. - /// - /// - public override UpdateSetDbCommandBuilder All() + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, false); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + var parameters = new List(); + var sql = new StringBuilder("UPDATE " + m_Table.Name.ToQuotedString()); + if (m_UpdateExpression == null) + { + sqlBuilder.BuildSetClause(sql, " SET ", null, null); + } + else { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + sql.Append(" SET " + m_UpdateExpression); + parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) + if (m_FilterValue != null) + { + sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions, true)); + parameters = sqlBuilder.GetParameters(DataSource); + } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + sql.Append(" WHERE " + m_WhereClause); + parameters.AddRange(sqlBuilder.GetParameters(DataSource)); + parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); + } + else + { + parameters.AddRange(sqlBuilder.GetParameters(DataSource)); + } + sql.Append(";"); - SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); + if (m_Parameters != null) + parameters.AddRange(m_Parameters); - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, false); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var updateCommand = new AccessCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); + updateCommand.ExecutionMode = AccessCommandExecutionMode.NonQuery; - var parameters = new List(); - var sql = new StringBuilder("UPDATE " + m_Table.Name.ToQuotedString()); - if (m_UpdateExpression == null) - { - sqlBuilder.BuildSetClause(sql, " SET ", null, null); - } - else - { - sql.Append(" SET " + m_UpdateExpression); - parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); - } + var desiredColumns = materializer.DesiredColumns(); + if (desiredColumns == Materializer.NoColumns) + return updateCommand; - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions, true)); - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - parameters.AddRange(sqlBuilder.GetParameters()); - parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); - } - else - { - parameters.AddRange(sqlBuilder.GetParameters()); - } - sql.Append(";"); + if (m_Options.HasFlag(UpdateOptions.ReturnOldValues)) + { + var result = PrepareRead(desiredColumns); + result.NextCommand = updateCommand; + return result; + } + else + { + updateCommand.NextCommand = PrepareRead(desiredColumns); + return updateCommand; + } + } - if (m_Parameters != null) - parameters.AddRange(m_Parameters); + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - var updateCommand = new AccessCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); - updateCommand.ExecutionMode = AccessCommandExecutionMode.NonQuery; + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - var desiredColumns = materializer.DesiredColumns(); - if (desiredColumns == Materializer.NoColumns) - return updateCommand; + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + return this; + } - if (m_Options.HasFlag(UpdateOptions.ReturnOldValues)) - { - var result = PrepareRead(desiredColumns); - result.NextCommand = updateCommand; - return result; - } - else - { - updateCommand.NextCommand = PrepareRead(desiredColumns); - return updateCommand; - } - } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = argumentValue; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + AccessCommandExecutionToken PrepareRead(IReadOnlyList desiredColumns) + { + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(desiredColumns); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + List parameters; + var sql = new StringBuilder(); + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + sql.Append(" FROM " + m_Table.Name.ToQuotedString()); + if (m_FilterValue != null) { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - return this; + sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions)); + parameters = sqlBuilder.GetParameters(DataSource); } - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) { - m_WhereClause = whereClause; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + sql.Append(" WHERE " + m_WhereClause); + parameters = SqlBuilder.GetParameters(m_WhereArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters(DataSource)); } - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + else { - m_WhereClause = whereClause; - m_WhereArgumentValue = argumentValue; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + parameters = sqlBuilder.GetParameters(DataSource); } + sql.Append(";"); - AccessCommandExecutionToken PrepareRead(IReadOnlyList desiredColumns) - { - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(desiredColumns); + if (m_Parameters != null) + parameters.AddRange(m_Parameters.Select(p => p.Clone())); - List parameters; - var sql = new StringBuilder(); - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - sql.Append(" FROM " + m_Table.Name.ToQuotedString()); - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions)); - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - parameters = SqlBuilder.GetParameters(m_WhereArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } - sql.Append(";"); - - if (m_Parameters != null) - parameters.AddRange(m_Parameters.Select(p => p.Clone())); - - return new AccessCommandExecutionToken(DataSource, "Query after updating " + m_Table.Name, sql.ToString(), parameters); - } + return new AccessCommandExecutionToken(DataSource, "Query after updating " + m_Table.Name, sql.ToString(), parameters); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Access/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.Access/Access/Utilities.cs index 2647778aa..f18fd89b4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Access/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/Access/Utilities.cs @@ -1,62 +1,68 @@ using System.Data.OleDb; using Tortuga.Chain.CommandBuilders; +using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Access +namespace Tortuga.Chain.Access; + +internal static class Utilities { - internal static class Utilities + public static OleDbParameter Clone(this OleDbParameter original) { - /// - /// Gets the parameters from a SQL Builder. - /// - /// The SQL builder. - /// - public static List GetParameters(this SqlBuilder sqlBuilder) + return new OleDbParameter() { - return sqlBuilder.GetParameters((SqlBuilderEntry entry) => - { - var result = new OleDbParameter(); - result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; + DbType = original.DbType, + Direction = original.Direction, + IsNullable = original.IsNullable, + OleDbType = original.OleDbType, + ParameterName = original.ParameterName, + Precision = original.Precision, + Scale = original.Scale, + Size = original.Size, + SourceColumn = original.SourceColumn, + SourceColumnNullMapping = original.SourceColumnNullMapping, + SourceVersion = original.SourceVersion, + Value = original.Value + }; + } + + public static List GetParameters(this SqlBuilder sqlBuilder, IDataSource dataSource) + { + return sqlBuilder.GetParameters(ParameterBuilderCallback); + } - if (entry.Details.DbType.HasValue) - result.OleDbType = entry.Details.DbType.Value; + public static List GetParametersKeysLast(this SqlBuilder sqlBuilder) + { + return sqlBuilder.GetParametersKeysLast(ParameterBuilderCallback); + } - return result; - }); - } + public static OleDbParameter ParameterBuilderCallback(SqlBuilderEntry entry) + { + var result = new OleDbParameter(); + result.ParameterName = entry.Details.SqlVariableName; - public static List GetParametersKeysLast(this SqlBuilder sqlBuilder) + result.Value = entry.ParameterValue switch { - return sqlBuilder.GetParametersKeysLast((SqlBuilderEntry entry) => - { - var result = new OleDbParameter(); - result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; +#if NET6_0_OR_GREATER + DateOnly dateOnly => dateOnly.ToDateTime(default), + TimeOnly timeOnly => default(DateTime) + timeOnly.ToTimeSpan(), +#endif + TimeSpan timeSpan => default(DateTime) + timeSpan, + _ => entry.ParameterValue + }; - if (entry.Details.DbType.HasValue) - result.OleDbType = entry.Details.DbType.Value; + if (entry.Details.DbType.HasValue) + result.OleDbType = entry.Details.DbType.Value; - return result; - }); - } + return result; + } - public static OleDbParameter Clone(this OleDbParameter original) + public static bool RequiresSorting(this AccessLimitOption limitOption) + { + return limitOption switch { - return new OleDbParameter() - { - DbType = original.DbType, - Direction = original.Direction, - IsNullable = original.IsNullable, - OleDbType = original.OleDbType, - ParameterName = original.ParameterName, - Precision = original.Precision, - Scale = original.Scale, - Size = original.Size, - SourceColumn = original.SourceColumn, - SourceColumnNullMapping = original.SourceColumnNullMapping, - SourceVersion = original.SourceVersion, - Value = original.Value - }; - } + AccessLimitOption.None => false, + AccessLimitOption.RowsWithTies => true, + _ => throw new ArgumentOutOfRangeException(nameof(limitOption), limitOption, "Unknown limit option") + }; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.Traits.cs b/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.Traits.cs index b078d8f19..b75fe3b5f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.Traits.cs @@ -9,7 +9,6 @@ namespace Tortuga.Chain; [UseTrait(typeof(Traits.RootDataSourceTrait))] partial class AccessDataSource { - private partial AccessTransactionalDataSource OnBeginTransaction(IsolationLevel? isolationLevel, bool forwardEvents) { var connection = CreateConnection(); @@ -20,7 +19,6 @@ private partial AccessTransactionalDataSource OnBeginTransaction(IsolationLevel? transaction = connection.BeginTransaction(isolationLevel.Value); return new AccessTransactionalDataSource(this, forwardEvents, connection, transaction); - } private partial async Task OnBeginTransactionAsync(IsolationLevel? isolationLevel, bool forwardEvents, CancellationToken cancellationToken) @@ -33,7 +31,6 @@ private partial async Task OnBeginTransactionAsyn transaction = connection.BeginTransaction(isolationLevel.Value); return new AccessTransactionalDataSource(this, forwardEvents, connection, transaction); - } private partial AbstractDataSource OnCloneWithOverrides(ICacheAdapter? cache, IEnumerable? additionalRules, object? userValue) @@ -67,4 +64,3 @@ private partial async Task OnCreateConnectionAsync(Cancellation private partial AccessOpenDataSource OnCreateOpenDataSource(AbstractConnection connection, AbstractTransaction? transaction) => new AccessOpenDataSource(this, connection, transaction); } - diff --git a/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.cs index 5f7fd7d53..0d5caac7e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/AccessDataSource.cs @@ -4,344 +4,328 @@ using Tortuga.Chain.Access; using Tortuga.Chain.Core; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class that represents a Access Data Source. +/// +public partial class AccessDataSource : AccessDataSourceBase { + AccessMetadataCache m_DatabaseMetadata; + /// - /// Class that represents a Access Data Source. + /// Initializes a new instance of the class. /// - public partial class AccessDataSource : AccessDataSourceBase + /// The name of the data source. + /// The connection string. + /// Optional settings object. + /// Connection string is null or empty.;connectionString + public AccessDataSource(string? name, string connectionString, AccessDataSourceSettings? settings = null) : base(settings) { - AccessMetadataCache m_DatabaseMetadata; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the data source. - /// The connection string. - /// Optional settings object. - /// Connection string is null or empty.;connectionString - public AccessDataSource(string? name, string connectionString, AccessDataSourceSettings? settings = null) : base(settings) - { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + + m_ConnectionBuilder = new OleDbConnectionStringBuilder(connectionString); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; + + m_DatabaseMetadata = new AccessMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - m_ConnectionBuilder = new OleDbConnectionStringBuilder(connectionString); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + /// + /// Initializes a new instance of the class. + /// + /// + /// Optional settings object. + public AccessDataSource(string connectionString, AccessDataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - m_DatabaseMetadata = new AccessMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + /// + /// Initializes a new instance of the class. + /// + /// The name of the data source. + /// The connection string builder. + /// Optional settings object. + /// connectionStringBuilder;connectionStringBuilder is null. + public AccessDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, AccessDataSourceSettings? settings = null) : base(settings) + { + m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); - /// - /// Initializes a new instance of the class. - /// - /// - /// Optional settings object. - public AccessDataSource(string connectionString, AccessDataSourceSettings? settings = null) - : this(null, connectionString, settings) - { - } + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; - /// - /// Initializes a new instance of the class. - /// - /// The name of the data source. - /// The connection string builder. - /// Optional settings object. - /// connectionStringBuilder;connectionStringBuilder is null. - public AccessDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, AccessDataSourceSettings? settings = null) : base(settings) - { - m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + m_DatabaseMetadata = new AccessMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + /// + /// Initializes a new instance of the class. + /// + /// + /// Optional settings object. + public AccessDataSource(OleDbConnectionStringBuilder connectionStringBuilder, AccessDataSourceSettings? settings = null) + : this(null, connectionStringBuilder, settings) + { + } - m_DatabaseMetadata = new AccessMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + AccessDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, AccessDataSourceSettings? settings, AccessMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + { + if (connectionStringBuilder == null) + throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + + m_ConnectionBuilder = connectionStringBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; + + m_DatabaseMetadata = databaseMetadata; + m_ExtensionCache = extensionCache; + m_Cache = cache; + } + + /// + /// This object can be used to lookup database information. + /// + public override AccessMetadataCache DatabaseMetadata => m_DatabaseMetadata; - /// - /// Initializes a new instance of the class. - /// - /// - /// Optional settings object. - public AccessDataSource(OleDbConnectionStringBuilder connectionStringBuilder, AccessDataSourceSettings? settings = null) - : this(null, connectionStringBuilder, settings) + /// + /// Creates a new data source with the indicated changes to the settings. + /// + /// The new settings to use. + /// + /// The new data source will share the same database metadata cache. + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public AccessDataSource WithSettings(AccessDataSourceSettings? settings) + { + var mergedSettings = new AccessDataSourceSettings() { - } + DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, + SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, + StrictMode = settings?.StrictMode ?? StrictMode, + SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode + }; + var result = new AccessDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); + result.m_DatabaseMetadata = m_DatabaseMetadata; + result.AuditRules = AuditRules; + result.UserValue = UserValue; + + result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); + result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); + result.ExecutionError += (sender, e) => OnExecutionError(e); + result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); + + return result; + } - AccessDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, AccessDataSourceSettings? settings, AccessMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + /// + /// Executes the specified operation. + /// + /// + /// + /// + [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var currentToken = executionToken as AccessCommandExecutionToken; + if (currentToken == null) + throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + + var startTime = DateTimeOffset.Now; + + try { - if (connectionStringBuilder == null) - throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + using (var con = CreateConnection()) + { + int? rows = null; + while (currentToken != null) + { + OnExecutionStarted(currentToken, startTime, state); + using (var cmd = new OleDbCommand()) + { + cmd.Connection = con; + currentToken.PopulateCommand(cmd, DefaultCommandTimeout); - m_ConnectionBuilder = connectionStringBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) + rows = implementation(cmd); + else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) + { + if (currentToken.ForwardResult == null) + throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - m_DatabaseMetadata = databaseMetadata; - m_ExtensionCache = extensionCache; - m_Cache = cache; + currentToken.ForwardResult(cmd.ExecuteScalar()); + } + else + rows = cmd.ExecuteNonQuery(); + currentToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); + } + currentToken = currentToken.NextCommand; + } + return rows; + } + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } - /// - /// This object can be used to lookup database information. - /// - public override AccessMetadataCache DatabaseMetadata => m_DatabaseMetadata; + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Creates a new data source with the indicated changes to the settings. - /// - /// The new settings to use. - /// - /// The new data source will share the same database metadata cache. - [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] - public AccessDataSource WithSettings(AccessDataSourceSettings? settings) + try { - var mergedSettings = new AccessDataSourceSettings() + using (var con = CreateConnection()) { - DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, - SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, - StrictMode = settings?.StrictMode ?? StrictMode, - SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode - }; - var result = new AccessDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); - result.m_DatabaseMetadata = m_DatabaseMetadata; - result.AuditRules = AuditRules; - result.UserValue = UserValue; - - result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); - result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); - result.ExecutionError += (sender, e) => OnExecutionError(e); - result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); - - return result; + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } } - - /// - /// Executes the specified operation. - /// - /// - /// - /// - [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var currentToken = executionToken as AccessCommandExecutionToken; - if (currentToken == null) - throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; + /// + /// Executes the specified operation asynchronously. + /// + /// + /// + /// + /// + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var currentToken = executionToken as AccessCommandExecutionToken; + if (currentToken == null) + throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + + var startTime = DateTimeOffset.Now; - try + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - using (var con = CreateConnection()) + int? rows = null; + while (currentToken != null) { - int? rows = null; - while (currentToken != null) + OnExecutionStarted(currentToken, startTime, state); + using (var cmd = new OleDbCommand()) { - OnExecutionStarted(currentToken, startTime, state); - using (var cmd = new OleDbCommand()) + cmd.Connection = con; + currentToken.PopulateCommand(cmd, DefaultCommandTimeout); + + if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) + rows = await implementation(cmd).ConfigureAwait(false); + else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = currentToken.CommandText; - cmd.CommandType = currentToken.CommandType; - foreach (var param in currentToken.Parameters) - cmd.Parameters.Add(param); - - currentToken.ApplyCommandOverrides(cmd); - - if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) - rows = implementation(cmd); - else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) - { - if (currentToken.ForwardResult == null) - throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - - currentToken.ForwardResult(cmd.ExecuteScalar()); - } - else - rows = cmd.ExecuteNonQuery(); - currentToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); + if (currentToken.ForwardResult == null) + throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); + + currentToken.ForwardResult(await cmd.ExecuteScalarAsync().ConfigureAwait(false)); } - currentToken = currentToken.NextCommand; + else + rows = await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); } - return rows; + currentToken = currentToken.NextCommand; } - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + return rows; } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = CreateConnection()) - { - var rows = implementation(con, null); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; } - catch (Exception ex) + else { OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); throw; } } + } - /// - /// Executes the specified operation asynchronously. - /// - /// - /// - /// - /// - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var currentToken = executionToken as AccessCommandExecutionToken; - if (currentToken == null) - throw new ArgumentNullException(nameof(executionToken), "only AccessCommandExecutionToken is supported."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try - { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - int? rows = null; - while (currentToken != null) - { - OnExecutionStarted(currentToken, startTime, state); - using (var cmd = new OleDbCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = currentToken.CommandText; - cmd.CommandType = currentToken.CommandType; - foreach (var param in currentToken.Parameters) - cmd.Parameters.Add(param); - - currentToken.ApplyCommandOverrides(cmd); - - if (currentToken.ExecutionMode == AccessCommandExecutionMode.Materializer) - rows = await implementation(cmd).ConfigureAwait(false); - else if (currentToken.ExecutionMode == AccessCommandExecutionMode.ExecuteScalarAndForward) - { - if (currentToken.ForwardResult == null) - throw new InvalidOperationException("currentToken.ExecutionMode is ExecuteScalarAndForward, but currentToken.ForwardResult is null."); - - currentToken.ForwardResult(await cmd.ExecuteScalarAsync().ConfigureAwait(false)); - } - else - rows = await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(currentToken, startTime, DateTimeOffset.Now, rows, state); - } - currentToken = currentToken.NextCommand; - } - return rows; - } - } - catch (Exception ex) + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/AccessExtensions.cs b/Tortuga.Chain/Tortuga.Chain.Access/AccessExtensions.cs index 196fe042f..22e2a095f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/AccessExtensions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/AccessExtensions.cs @@ -2,48 +2,47 @@ using System.Data.OleDb; using Tortuga.Chain.Access; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class SqlServerExtensions. +/// +public static class AccessExtensions { + readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + /// - /// Class SqlServerExtensions. + /// Returns a data source wrapped around the connection. /// - public static class AccessExtensions + /// The connection. + /// SqlServerOpenDataSource. + /// + public static AccessOpenDataSource AsDataSource(this OleDbConnection connection) { - readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - /// - /// Returns a data source wrapped around the connection. - /// - /// The connection. - /// SqlServerOpenDataSource. - /// - public static AccessOpenDataSource AsDataSource(this OleDbConnection connection) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); - - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new AccessDataSource(cs)); - return new AccessOpenDataSource(dataSourceBase, connection, null); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new AccessDataSource(cs)); + return new AccessOpenDataSource(dataSourceBase, connection, null); + } - /// - /// Returns a data source wrapped around the transaction. - /// - /// The connection. - /// The transaction. - /// SqlServerOpenDataSource. - /// - public static AccessOpenDataSource AsDataSource(this OleDbConnection connection, OleDbTransaction transaction) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); + /// + /// Returns a data source wrapped around the transaction. + /// + /// The connection. + /// The transaction. + /// SqlServerOpenDataSource. + /// + public static AccessOpenDataSource AsDataSource(this OleDbConnection connection, OleDbTransaction transaction) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new AccessDataSource(cs)); - return new AccessOpenDataSource(dataSourceBase, connection, transaction); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new AccessDataSource(cs)); + return new AccessOpenDataSource(dataSourceBase, connection, transaction); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/AccessLimitOption.cs b/Tortuga.Chain/Tortuga.Chain.Access/AccessLimitOption.cs index 500dff650..d60e322d3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/AccessLimitOption.cs +++ b/Tortuga.Chain/Tortuga.Chain.Access/AccessLimitOption.cs @@ -1,20 +1,18 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Limit options supported by Access. +/// +/// This is a strict subset of LimitOptions +public enum AccessLimitOption { /// - /// Limit options supported by Access. + /// No limits were applied. /// - /// This is a strict subset of LimitOptions - public enum AccessLimitOption - { - /// - /// No limits were applied. - /// - None = LimitOptions.None, - - /// - /// Uses TOP - /// - RowsWithTies = LimitOptions.RowsWithTies, + None = LimitOptions.None, - } + /// + /// Uses TOP + /// + RowsWithTies = LimitOptions.RowsWithTies, } diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index 551ff960e..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,25 +0,0 @@ -/* -Container class: Tortuga.Chain.AccessDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.Access.AccessDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait -Container class: Tortuga.Chain.Access.AccessOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.Access.AccessTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessDataSourceBase.cs deleted file mode 100644 index 34ba65b52..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessDataSourceBase.cs +++ /dev/null @@ -1,980 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.Access -{ - partial class AccessDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Traits.ICommandHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait1 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsUpdateTrait ___Trait2 = new(); - private Traits.SupportsUpdateTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsDeleteTrait ___Trait3 = new(); - private Traits.SupportsDeleteTrait __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait4 = new(); - private Traits.SupportsSqlQueriesTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait5 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsInsertTrait ___Trait6 = new(); - private Traits.SupportsInsertTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsUpdateSet ___Trait7 = new(); - private Traits.SupportsUpdateSet __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsDeleteSet ___Trait8 = new(); - private Traits.SupportsDeleteSet __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsFromTrait ___Trait9 = new(); - private Traits.SupportsFromTrait __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait10 = new(); - private Traits.SupportsGetByKeyListTrait __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait3).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait3).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait1).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait1).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait1).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait8).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait8).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait8).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait9).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait10).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait10).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait10).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait10).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait10).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait10).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait10).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait6).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait6).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait4).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait2).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait2).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait5).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait5).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait5).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait7).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait7).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait7).UpdateSet(tableName, newValues, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.Access.AccessObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.Access.AccessObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait1.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.Access.AccessObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait1.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait1.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait1.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait1.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait1.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.Access.AccessObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait1.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.Access.AccessObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait8.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait8.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.Access.AccessObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait8.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait8.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.Access.AccessObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait3.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait3.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.Access.AccessObjectName tableOrViewName) - { - return __Trait9.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.Access.AccessObjectName tableOrViewName, System.String whereClause) - { - return __Trait9.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.Access.AccessObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait9.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.Access.AccessObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait9.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait9.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait9.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait9.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait9.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait10.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait10.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait10.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait10.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait10.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.Access.AccessObjectName tableName, System.String key) - { - return __Trait10.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.Access.AccessObjectName tableName, TKey key) - { - return __Trait10.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.Access.AccessObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait10.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait10.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait10.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait10.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait10.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait10.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait10.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait6.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.Access.AccessObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait6.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait4.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait4.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.Access.AccessObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait5.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.Access.AccessObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait5.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.Access.AccessObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait5.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.Access.AccessObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.Access.AccessObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.Access.AccessObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait2.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.Access.AccessObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait2.Update(tableName, argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.Access.AccessObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.DataSource = this; - __Trait2.DataSource = this; - __Trait3.DataSource = this; - __Trait4.OnSql = OnSql; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessOpenDataSource.cs deleted file mode 100644 index 4386c0078..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.Access -{ - partial class AccessOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.OleDb.OleDbConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.OleDb.OleDbTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.Access.AccessMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.AccessDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.OleDb.OleDbConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Data.OleDb.OleDbTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.Access.AccessOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.Access.AccessOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.Access.AccessOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.Access.AccessOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessTransactionalDataSource.cs deleted file mode 100644 index 0753d3cbe..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.Access.AccessTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.Access -{ - partial class AccessTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.OleDb.OleDbConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.OleDb.OleDbTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.Access.AccessMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.AccessDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.OleDb.OleDbConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private System.Data.OleDb.OleDbTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.AccessDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.AccessDataSource.cs deleted file mode 100644 index fde40b285..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Access/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.AccessDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class AccessDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.Access.AccessTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.Access.AccessTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public System.Data.OleDb.OleDbConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.Access.AccessOpenDataSource CreateOpenDataSource(System.Data.OleDb.OleDbConnection connection, System.Data.OleDb.OleDbTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.Access.AccessOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private System.Data.OleDb.OleDbConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.AccessDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.AccessDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.AccessDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.AccessDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.Access.AccessTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.AccessDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial System.Data.OleDb.OleDbConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.Access.AccessOpenDataSource OnCreateOpenDataSource(System.Data.OleDb.OleDbConnection connection, System.Data.OleDb.OleDbTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.Access/Tortuga.Chain.Access.csproj b/Tortuga.Chain/Tortuga.Chain.Access/Tortuga.Chain.Access.csproj index 8ecdf6b9b..a00492b37 100644 --- a/Tortuga.Chain/Tortuga.Chain.Access/Tortuga.Chain.Access.csproj +++ b/Tortuga.Chain/Tortuga.Chain.Access/Tortuga.Chain.Access.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -57,7 +57,7 @@ - + @@ -85,7 +85,7 @@ - true + Generated @@ -93,7 +93,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/CompiledMaterializers.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/CompiledMaterializers.cs index 63ea2d165..a8b4ba1ac 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/CompiledMaterializers.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/CompiledMaterializers.cs @@ -9,332 +9,360 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Utility class that enables access to the compiled version of the Object and Collection materializers. +/// +public static class CompiledMaterializers { /// - /// Utility class that enables access to the compiled version of the Object and Collection materializers. + /// Occurs when a materializer is compiled. + /// + public static event EventHandler? MaterializerCompiled; + + /// + /// Occurs when materializer fails to compile. /// - public static class CompiledMaterializers + public static event EventHandler? MaterializerCompilerFailed; + + /// + /// Allows compilation of the ToObject materializer. + /// + /// The type of the command. + /// The type of the parameter. + /// The command builder. + /// + public static CompiledSingleRow Compile(this SingleRowDbCommandBuilder commandBuilder) + where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// Occurs when a materializer is compiled. - /// - public static event EventHandler? MaterializerCompiled; - - /// - /// Occurs when materializer fails to compile. - /// - public static event EventHandler? MaterializerCompilerFailed; - - /// - /// Allows compilation of the ToObject materializer. - /// - /// The type of the command. - /// The type of the parameter. - /// The command builder. - /// - public static CompiledSingleRow Compile(this SingleRowDbCommandBuilder commandBuilder) - where TCommand : DbCommand - where TParameter : DbParameter - { - return new CompiledSingleRow(commandBuilder); - } + return new CompiledSingleRow(commandBuilder); + } - /// - /// Allows compilation of the ToObject materializer. - /// - /// The type of the command. - /// The type of the parameter. - /// The type of the object to be constructed. - /// The command builder. - /// - public static CompiledSingleRow Compile(this SingleRowDbCommandBuilder commandBuilder) - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class, new() - { - return new CompiledSingleRow(commandBuilder); - } + /// + /// Allows compilation of the ToObject materializer. + /// + /// The type of the command. + /// The type of the parameter. + /// The type of the object to be constructed. + /// The command builder. + /// + public static CompiledSingleRow Compile(this SingleRowDbCommandBuilder commandBuilder) + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class, new() + { + return new CompiledSingleRow(commandBuilder); + } - /// - /// Allows compilation of the ToObject and ToCollection materializer. - /// - /// The type of the command. - /// The type of the parameter. - /// The command builder. - /// - public static CompiledMultipleRow Compile(this MultipleRowDbCommandBuilder commandBuilder) - where TCommand : DbCommand - where TParameter : DbParameter - { - return new CompiledMultipleRow(commandBuilder); - } + /// + /// Allows compilation of the ToObject and ToCollection materializer. + /// + /// The type of the command. + /// The type of the parameter. + /// The command builder. + /// + public static CompiledMultipleRow Compile(this MultipleRowDbCommandBuilder commandBuilder) + where TCommand : DbCommand + where TParameter : DbParameter + { + return new CompiledMultipleRow(commandBuilder); + } - /// - /// Allows compilation of the ToObject and ToCollection materializer. - /// - /// The type of the command. - /// The type of the parameter. - /// The type of the limit option. - /// The type of the object to be constructed. - /// The command builder. - public static CompiledMultipleRow Compile(this TableDbCommandBuilder commandBuilder) - where TCommand : DbCommand - where TParameter : DbParameter - where TLimit : struct //really an enum - where TObject : class, new() - { - return new CompiledMultipleRow(commandBuilder); - } + /// + /// Allows compilation of the ToObject and ToCollection materializer. + /// + /// The type of the command. + /// The type of the parameter. + /// The type of the limit option. + /// The type of the object to be constructed. + /// The command builder. + public static CompiledMultipleRow Compile(this TableDbCommandBuilder commandBuilder) + where TCommand : DbCommand + where TParameter : DbParameter + where TLimit : struct //really an enum + where TObject : class, new() + { + return new CompiledMultipleRow(commandBuilder); + } - /// - /// Allows compilation of the ToObject and ToCollection materializer. - /// - /// The type of the command. - /// The type of the parameter. - /// The command builder. - /// - public static CompiledMultipleTable Compile(this MultipleTableDbCommandBuilder commandBuilder) - where TCommand : DbCommand - where TParameter : DbParameter - { - return new CompiledMultipleTable(commandBuilder); - } + /// + /// Allows compilation of the ToObject and ToCollection materializer. + /// + /// The type of the command. + /// The type of the parameter. + /// The command builder. + /// + public static CompiledMultipleTable Compile(this MultipleTableDbCommandBuilder commandBuilder) + where TCommand : DbCommand + where TParameter : DbParameter + { + return new CompiledMultipleTable(commandBuilder); + } - /// - /// Creates the builder. - /// - /// The type of the object. - /// The data source. - /// The SQL. - /// The reader. - /// A list of columns known to be non-nullable. - /// - [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - internal static MethodDelegate CreateBuilder(IDataSource dataSource, string sql, IDataReader reader, IReadOnlyList nonNullableColumns) - where TObject : new() - { - var cache = dataSource.GetExtensionData(); - var result = cache.GetBuilder(sql); - if (result != null) - return result; + /// + /// Creates the builder. + /// + /// The type of the object. + /// The data source. + /// The SQL. + /// The reader. + /// A list of columns known to be non-nullable. + /// + [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + internal static MethodDelegate CreateBuilder(IDataSource dataSource, string sql, IDataReader reader, IReadOnlyList nonNullableColumns) + where TObject : new() + { + var cache = dataSource.GetExtensionData(); + var result = cache.GetBuilder(sql); + if (result != null) + return result; - var code = new StringBuilder(); + var code = new StringBuilder(); - var typeName = MetadataCache.GetMetadata(typeof(TObject)).CSharpFullName; + var typeName = MetadataCache.GetMetadata(typeof(TObject)).CSharpFullName; - var changeTracker = typeof(TObject).GetInterfaces().Any(x => x == typeof(IChangeTracking)); + var changeTracker = typeof(TObject).GetInterfaces().Any(x => x == typeof(IChangeTracking)); - var columns = new Dictionary(StringComparer.OrdinalIgnoreCase); - for (var i = 0; i < reader.FieldCount; i++) - { - var columnName = reader.GetName(i); - var columnType = reader.GetFieldType(i); - //var columnTypeName = columnType.FullName; - string getter; - if (columnType == typeof(bool)) getter = "reader.GetBoolean"; - else if (columnType == typeof(byte)) getter = "reader.GetByte"; - else if (columnType == typeof(char)) getter = "reader.GetChar"; - else if (columnType == typeof(DateTime)) getter = "reader.GetDateTime"; - else if (columnType == typeof(decimal)) getter = "reader.GetDecimal"; - else if (columnType == typeof(double)) getter = "reader.GetDouble"; - else if (columnType == typeof(float)) getter = "reader.GetFloat"; - else if (columnType == typeof(Guid)) getter = "reader.GetGuid"; - else if (columnType == typeof(short)) getter = "reader.GetInt16"; - else if (columnType == typeof(int)) getter = "reader.GetInt32"; - else if (columnType == typeof(long)) getter = "reader.GetInt64"; - else if (columnType == typeof(string)) getter = "reader.GetString"; - else if (columnType == typeof(byte[])) getter = "(byte[])reader.GetValue"; - else if (columnType == typeof(UInt16)) getter = "(System.UInt16)reader.GetValue"; - else if (columnType == typeof(UInt32)) getter = "(System.UInt32)reader.GetValue"; - else if (columnType == typeof(UInt64)) getter = "(System.UInt64)reader.GetValue"; - else getter = "reader.GetValue"; - - var isNullable = !nonNullableColumns.Any(c => c.SqlName == columnName); //Assume column is nullable unless proven otherwise - columns.Add(columnName, new ColumnData(i, columnType, getter, isNullable)); - } + var columns = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (var i = 0; i < reader.FieldCount; i++) + { + var columnName = reader.GetName(i); + var columnType = reader.GetFieldType(i); + //var columnTypeName = columnType.FullName; + string getter; + if (columnType == typeof(bool)) getter = "reader.GetBoolean"; + else if (columnType == typeof(byte)) getter = "reader.GetByte"; + else if (columnType == typeof(char)) getter = "reader.GetChar"; + else if (columnType == typeof(DateTime)) getter = "reader.GetDateTime"; + else if (columnType == typeof(TimeSpan)) getter = "(System.TimeSpan)reader.GetValue"; + else if (columnType == typeof(decimal)) getter = "reader.GetDecimal"; + else if (columnType == typeof(double)) getter = "reader.GetDouble"; + else if (columnType == typeof(float)) getter = "reader.GetFloat"; + else if (columnType == typeof(Guid)) getter = "reader.GetGuid"; + else if (columnType == typeof(short)) getter = "reader.GetInt16"; + else if (columnType == typeof(int)) getter = "reader.GetInt32"; + else if (columnType == typeof(long)) getter = "reader.GetInt64"; + else if (columnType == typeof(string)) getter = "reader.GetString"; + else if (columnType == typeof(byte[])) getter = "(byte[])reader.GetValue"; + else if (columnType == typeof(UInt16)) getter = "(System.UInt16)reader.GetValue"; + else if (columnType == typeof(UInt32)) getter = "(System.UInt32)reader.GetValue"; + else if (columnType == typeof(UInt64)) getter = "(System.UInt64)reader.GetValue"; + else getter = "reader.GetValue"; + + var isNullable = !nonNullableColumns.Any(c => c.SqlName == columnName); //Assume column is nullable unless proven otherwise + columns.Add(columnName, new ColumnData(i, columnType, getter, isNullable)); + } - var evaluator = CSScript.RoslynEvaluator.Reset(false); - //evaluator = evaluator.ReferenceAssemblyOf(); - //evaluator = evaluator.ReferenceAssemblyOf(); - //evaluator = evaluator.ReferenceAssemblyOf(); - evaluator = evaluator.ReferenceAssemblyOf(reader); - evaluator = AugmentScriptEvaluator(evaluator, typeof(TObject)); + var evaluator = CSScript.RoslynEvaluator.Reset(false); + //evaluator = evaluator.ReferenceAssemblyOf(); + //evaluator = evaluator.ReferenceAssemblyOf(); + //evaluator = evaluator.ReferenceAssemblyOf(); + evaluator = evaluator.ReferenceAssemblyOf(reader); + evaluator = AugmentScriptEvaluator(evaluator, typeof(TObject)); - //We need a public version of the DataReader class. - //If we can't find one, default to the slower IDataReader interface. - var readerType = reader.GetType(); - while (!readerType.IsPublic) - readerType = readerType.BaseType!; - if (readerType.GetInterface("IDataReader") == null) - readerType = typeof(IDataReader); + //We need a public version of the DataReader class. + //If we can't find one, default to the slower IDataReader interface. + var readerType = reader.GetType(); + while (!readerType.IsPublic) + readerType = readerType.BaseType!; + if (readerType.GetInterface("IDataReader") == null) + readerType = typeof(IDataReader); - code.AppendLine($"{typeName} Load({readerType.FullName} reader)"); - code.AppendLine("{"); - code.AppendLine($" var result = new {typeName}();"); + code.AppendLine($"{typeName} Load({readerType.FullName} reader)"); + code.AppendLine("{"); + code.AppendLine($" var result = new {typeName}();"); - var properties = MetadataCache.GetMetadata(typeof(TObject)).Properties; - var path = "result"; + var properties = MetadataCache.GetMetadata(typeof(TObject)).Properties; + var path = "result"; - ConstructDecomposedObjects(code, path, properties); + ConstructDecomposedObjects(code, path, properties); - //This loop is slow, but it ensure that we always generate the reader.GetXxx methods in the correct order. - for (var i = 0; i < reader.FieldCount; i++) - { - SetProperties(code, columns, properties, i, "result", null); - } + //This loop is slow, but it ensure that we always generate the reader.GetXxx methods in the correct order. + for (var i = 0; i < reader.FieldCount; i++) + { + SetProperties(code, columns, properties, i, "result", null); + } - if (changeTracker) - code.AppendLine(" ((System.ComponentModel.IChangeTracking)result).AcceptChanges();"); + if (changeTracker) + code.AppendLine(" ((System.ComponentModel.IChangeTracking)result).AcceptChanges();"); - code.AppendLine(" return result;"); - code.AppendLine("}"); + code.AppendLine(" return result;"); + code.AppendLine("}"); - var codeToString = code.ToString(); - try - { - result = evaluator.CreateDelegate(codeToString); + var codeToString = code.ToString(); + try + { + result = evaluator.CreateDelegate(codeToString); - MaterializerCompiled?.Invoke(typeof(CompiledMaterializers), new MaterializerCompilerEventArgs(dataSource, sql, codeToString, typeof(TObject))); + MaterializerCompiled?.Invoke(typeof(CompiledMaterializers), new MaterializerCompilerEventArgs(dataSource, sql, codeToString, typeof(TObject))); - cache.StoreBuilder(sql, result); + cache.StoreBuilder(sql, result); - return result; - } - catch (Exception ex) - { - MaterializerCompilerFailed?.Invoke(typeof(CompiledMaterializers), new MaterializerCompilerEventArgs(dataSource, sql, codeToString, typeof(TObject))); - - //Debug.WriteLine(codeToString); - //foreach (var item in evaluator.GetReferencedAssemblies()) - // Debug.WriteLine("Referenced Assembly: " + item.FullName); - ex.Data["Code"] = codeToString; - //ex.Data["Evaluator"] = evaluator; - throw; - } + return result; } - - /// - /// Creates the script evaluator by ensuring that all of the relevant assemblies are loaded. - /// - /// The evaluator. - /// The type. - /// - private static IEvaluator AugmentScriptEvaluator(IEvaluator evaluator, Type type) + catch (Exception ex) { - evaluator = evaluator.ReferenceAssembly(type.Assembly); + MaterializerCompilerFailed?.Invoke(typeof(CompiledMaterializers), new MaterializerCompilerEventArgs(dataSource, sql, codeToString, typeof(TObject))); + + //Debug.WriteLine(codeToString); + //foreach (var item in evaluator.GetReferencedAssemblies()) + // Debug.WriteLine("Referenced Assembly: " + item.FullName); + ex.Data["Code"] = codeToString; + //ex.Data["Evaluator"] = evaluator; + throw; + } + } - if (type.BaseType != typeof(object)) - evaluator = AugmentScriptEvaluator(evaluator, type.BaseType!); + /// + /// Creates the script evaluator by ensuring that all of the relevant assemblies are loaded. + /// + /// The evaluator. + /// The type. + /// + private static IEvaluator AugmentScriptEvaluator(IEvaluator evaluator, Type type) + { + evaluator = evaluator.ReferenceAssembly(type.Assembly); - foreach (var property in MetadataCache.GetMetadata(type).Properties.Where(p => p.Decompose)) - evaluator = AugmentScriptEvaluator(evaluator, property.PropertyType); + if (type.BaseType != typeof(object)) + evaluator = AugmentScriptEvaluator(evaluator, type.BaseType!); - return evaluator; - } + foreach (var property in MetadataCache.GetMetadata(type).Properties.Where(p => p.Decompose)) + evaluator = AugmentScriptEvaluator(evaluator, property.PropertyType); + + return evaluator; + } - /// - /// Constructs the decomposed objects as necessary. - /// - /// The code. - /// The path. - /// The properties. - private static void ConstructDecomposedObjects(StringBuilder code, string path, PropertyMetadataCollection properties) + /// + /// Constructs the decomposed objects as necessary. + /// + /// The code. + /// The path. + /// The properties. + private static void ConstructDecomposedObjects(StringBuilder code, string path, PropertyMetadataCollection properties) + { + foreach (var property in properties) { - foreach (var property in properties) + if (property.Decompose) { - if (property.Decompose) + if (property.CanWrite) { - if (property.CanWrite) - { - code.AppendLine($" if ({path}.{property.Name} == null)"); - code.AppendLine($" {path}.{property.Name} = new {property.PropertyType.FullName}();"); - } - - ConstructDecomposedObjects(code, path + "." + property.Name, MetadataCache.GetMetadata(property.PropertyType).Properties); + code.AppendLine($" if ({path}.{property.Name} == null)"); + code.AppendLine($" {path}.{property.Name} = new {property.PropertyType.FullName}();"); } + + ConstructDecomposedObjects(code, path + "." + property.Name, MetadataCache.GetMetadata(property.PropertyType).Properties); } } + } - /// - /// Sets the properties. - /// - /// The code being generated. - /// The columns in the data reader. - /// The properties for the current object. - /// Index of the column being read. - /// The path to the object whose properties are being set. - /// The decomposition prefix used when reading the column data. - private static void SetProperties(StringBuilder code, Dictionary columns, PropertyMetadataCollection properties, int columnIndex, string path, string? decompositionPrefix) + /// + /// Sets the properties. + /// + /// The code being generated. + /// The columns in the data reader. + /// The properties for the current object. + /// Index of the column being read. + /// The path to the object whose properties are being set. + /// The decomposition prefix used when reading the column data. + private static void SetProperties(StringBuilder code, Dictionary columns, PropertyMetadataCollection properties, int columnIndex, string path, string? decompositionPrefix) + { + foreach (var property in properties) { - foreach (var property in properties) + if (property.Decompose) { - if (property.Decompose) - { - SetProperties(code, columns, MetadataCache.GetMetadata(property.PropertyType).Properties, columnIndex, path + "." + property.Name, decompositionPrefix + property.DecompositionPrefix); - } + SetProperties(code, columns, MetadataCache.GetMetadata(property.PropertyType).Properties, columnIndex, path + "." + property.Name, decompositionPrefix + property.DecompositionPrefix); + } - if (property.MappedColumnName == null) - continue; + if (property.MappedColumnName == null) + continue; - if (!columns.TryGetValue(decompositionPrefix + property.MappedColumnName, out var column)) - continue; //not a valid column + if (!columns.TryGetValue(decompositionPrefix + property.MappedColumnName, out var column)) + continue; //not a valid column - if (column.Index != columnIndex) - continue; //we'll get it on another iteration + if (column.Index != columnIndex) + continue; //we'll get it on another iteration - if (property.PropertyType == column.ColumnType || (string.Equals(property.PropertyType.Name, "Nullable`1", StringComparison.Ordinal) && property.PropertyType.IsGenericType && property.PropertyType.GenericTypeArguments[0] == column.ColumnType)) + if (property.PropertyType == column.ColumnType || (string.Equals(property.PropertyType.Name, "Nullable`1", StringComparison.Ordinal) && property.PropertyType.IsGenericType && property.PropertyType.GenericTypeArguments[0] == column.ColumnType)) + { + if (column.IsNullable && (property.PropertyType.IsClass || (string.Equals(property.PropertyType.Name, "Nullable`1", StringComparison.Ordinal) && property.PropertyType.IsGenericType))) { - if (column.IsNullable && (property.PropertyType.IsClass || (string.Equals(property.PropertyType.Name, "Nullable`1", StringComparison.Ordinal) && property.PropertyType.IsGenericType))) - { - //null handler - code.AppendLine($" if (reader.IsDBNull({column.Index}))"); - code.AppendLine($" {path}.{property.Name} = null;"); - code.AppendLine($" else"); - code.AppendLine($" {path}.{property.Name} = {column.Getter}({column.Index});"); - } - else - { - //non-null handler - code.AppendLine($" {path}.{property.Name} = {column.Getter}({column.Index});"); - } + //null handler + code.AppendLine($" if (reader.IsDBNull({column.Index}))"); + code.AppendLine($" {path}.{property.Name} = null;"); + code.AppendLine($" else"); + code.AppendLine($" {path}.{property.Name} = {column.Getter}({column.Index});"); } - else //type casting is required + else { - var propertyTypeName = MetadataCache.GetMetadata(property.PropertyType).CSharpFullName; - - if (column.IsNullable && (property.PropertyType.IsClass || (string.Equals(property.PropertyType.Name, "Nullable`1", StringComparison.Ordinal) && property.PropertyType.IsGenericType))) - { - //null handler - code.AppendLine($" if (reader.IsDBNull({column.Index}))"); - code.AppendLine($" {path}.{property.Name} = null;"); - code.AppendLine($" else"); - code.AppendLine($" {path}.{property.Name} = ({propertyTypeName}){column.Getter}({column.Index});"); - } - else - { - //non-null handler - code.AppendLine($" {path}.{property.Name} = ({propertyTypeName}){column.Getter}({column.Index});"); - } + //non-null handler + code.AppendLine($" {path}.{property.Name} = {column.Getter}({column.Index});"); } } - } - - private class ColumnData - { - public ColumnData(int index, Type columnType, string getter, bool isNullable) + else //type casting is required { - ColumnType = columnType; - Getter = getter; - Index = index; - IsNullable = isNullable; + var propertyTypeName = MetadataCache.GetMetadata(property.PropertyType).CSharpFullName; + + string getterWithConversion; + + //special handling for OleDB + if (property.PropertyType == typeof(TimeSpan) && column.ColumnType == typeof(string)) + getterWithConversion = $"TimeSpan.Parse({column.Getter}({column.Index}), System.Globalization.CultureInfo.InvariantCulture);"; + else if (property.PropertyType == typeof(TimeSpan) && column.ColumnType == typeof(object)) + getterWithConversion = $"TimeSpan.Parse((string){column.Getter}({column.Index}), System.Globalization.CultureInfo.InvariantCulture);"; + else if (property.PropertyType == typeof(TimeSpan) && column.ColumnType == typeof(DateTime)) + getterWithConversion = $"({column.Getter}({column.Index})).TimeOfDay"; + +#if NET6_0_OR_GREATER + else if (property.PropertyType == typeof(DateOnly) && column.ColumnType == typeof(DateTime)) + getterWithConversion = $"DateOnly.FromDateTime({column.Getter}({column.Index}))"; + else if (property.PropertyType == typeof(TimeOnly) && column.ColumnType == typeof(DateTime)) + getterWithConversion = $"TimeOnly.FromDateTime({column.Getter}({column.Index}))"; + else if (property.PropertyType == typeof(TimeOnly) && column.ColumnType == typeof(TimeSpan)) + getterWithConversion = $"TimeOnly.FromTimeSpan({column.Getter}({column.Index}))"; + + //special handling for OleDB + else if (property.PropertyType == typeof(TimeOnly) && column.ColumnType == typeof(string)) + getterWithConversion = $"TimeOnly.Parse({column.Getter}({column.Index}), System.Globalization.CultureInfo.InvariantCulture);"; + else if (property.PropertyType == typeof(TimeOnly) && column.ColumnType == typeof(object)) + getterWithConversion = $"TimeOnly.Parse((string){column.Getter}({column.Index}), System.Globalization.CultureInfo.InvariantCulture);"; +#endif + else + //simple casting + getterWithConversion = $"({propertyTypeName}){column.Getter}({column.Index})"; + + if (column.IsNullable && (property.PropertyType.IsClass || (string.Equals(property.PropertyType.Name, "Nullable`1", StringComparison.Ordinal) && property.PropertyType.IsGenericType))) + { + //null handler + code.AppendLine($" if (reader.IsDBNull({column.Index}))"); + code.AppendLine($" {path}.{property.Name} = null;"); + code.AppendLine($" else"); + code.AppendLine($" {path}.{property.Name} = {getterWithConversion};"); + } + else + { + //non-null handler + code.AppendLine($" {path}.{property.Name} = {getterWithConversion};"); + } } + } + } - public Type ColumnType { get; } - public string Getter { get; } - public int Index { get; } - public bool IsNullable { get; } + private class ColumnData + { + public ColumnData(int index, Type columnType, string getter, bool isNullable) + { + ColumnType = columnType; + Getter = getter; + Index = index; + IsNullable = isNullable; } + + public Type ColumnType { get; } + public string Getter { get; } + public int Index { get; } + public bool IsNullable { get; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/MaterializerCompilerEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/MaterializerCompilerEventArgs.cs index 0bd95da41..41245fd90 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/MaterializerCompilerEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/MaterializerCompilerEventArgs.cs @@ -1,59 +1,58 @@ using Tortuga.Chain.DataSources; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class MaterializerCompiledEventArgs. +/// +public class MaterializerCompilerEventArgs : EventArgs { /// - /// Class MaterializerCompiledEventArgs. + /// Initializes a new instance of the class. /// - public class MaterializerCompilerEventArgs : EventArgs + /// The data source. + /// The SQL. + /// The code. + /// Type of the target. + /// The exception. + public MaterializerCompilerEventArgs(IDataSource dataSource, string sql, string code, Type targetType, Exception? exception = null) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The SQL. - /// The code. - /// Type of the target. - /// The exception. - public MaterializerCompilerEventArgs(IDataSource dataSource, string sql, string code, Type targetType, Exception? exception = null) - { - Exception = exception; - TargetType = targetType; - Code = code; - Sql = sql; - DataSource = dataSource; - } + Exception = exception; + TargetType = targetType; + Code = code; + Sql = sql; + DataSource = dataSource; + } - /// - /// Gets the code. - /// - /// The code. - public string Code { get; } + /// + /// Gets the code. + /// + /// The code. + public string Code { get; } - /// - /// Gets the data source. - /// - /// The data source. - public IDataSource DataSource { get; } + /// + /// Gets the data source. + /// + /// The data source. + public IDataSource DataSource { get; } - /// - /// Gets the exception. - /// - /// - /// The exception. - /// - public Exception? Exception { get; } + /// + /// Gets the exception. + /// + /// + /// The exception. + /// + public Exception? Exception { get; } - /// - /// Gets the SQL. - /// - /// The SQL. - public string Sql { get; } + /// + /// Gets the SQL. + /// + /// The SQL. + public string Sql { get; } - /// - /// Gets the type of the target. - /// - /// The type of the target. - public Type TargetType { get; } - } + /// + /// Gets the type of the target. + /// + /// The type of the target. + public Type TargetType { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledCollectionMaterializer.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledCollectionMaterializer.cs index 975054690..c5d61f5cc 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledCollectionMaterializer.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledCollectionMaterializer.cs @@ -2,66 +2,65 @@ using Tortuga.Anchor.Metadata; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal sealed class CompiledCollectionMaterializer : Materializer + where TCommand : DbCommand + where TObject : class, new() + where TCollection : ICollection, new() + where TParameter : DbParameter { - internal sealed class CompiledCollectionMaterializer : Materializer - where TCommand : DbCommand - where TObject : class, new() - where TCollection : ICollection, new() - where TParameter : DbParameter + /// + /// Initializes a new instance of the class. + /// + /// The associated operation. + /// The collection options. + /// Compiled materializers do not support non-default constructors + public CompiledCollectionMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) + : base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - /// The collection options. - /// Compiled materializers do not support non-default constructors - public CompiledCollectionMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) - : base(commandBuilder) - { - if (collectionOptions.HasFlag(CollectionOptions.InferConstructor)) - throw new NotSupportedException("Compiled materializers do not support non-default constructors"); - } + if (collectionOptions.HasFlag(CollectionOptions.InferConstructor)) + throw new NotSupportedException("Compiled materializers do not support non-default constructors"); + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - public override IReadOnlyList DesiredColumns() => MetadataCache.GetMetadata(typeof(TObject)).ColumnsFor; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + public override IReadOnlyList DesiredColumns() => MetadataCache.GetMetadata(typeof(TObject)).ColumnsFor; - public override TCollection Execute(object? state = null) + public override TCollection Execute(object? state = null) + { + var result = new TCollection(); + Prepare().Execute(cmd => { - var result = new TCollection(); - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); - while (reader.Read()) - result.Add(factory(reader)); - return result.Count; - } - }, state); + var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); + while (reader.Read()) + result.Add(factory(reader)); + return result.Count; + } + }, state); - return result; - } + return result; + } - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new TCollection(); + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new TCollection(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); - while (await reader.ReadAsync().ConfigureAwait(false)) - result.Add(factory(reader)); - return result.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); + while (await reader.ReadAsync().ConfigureAwait(false)) + result.Add(factory(reader)); + return result.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`2.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`2.cs index a3d75770e..038342691 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`2.cs @@ -2,78 +2,77 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Extension for using compiled materializers with Tortuga Chain +/// +/// The type of the command. +/// The type of the parameter. +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct CompiledMultipleRow + where TCommand : DbCommand + where TParameter : DbParameter { + readonly MultipleRowDbCommandBuilder m_CommandBuilder; + /// - /// Extension for using compiled materializers with Tortuga Chain + /// Initializes a new instance of the struct. /// - /// The type of the command. - /// The type of the parameter. - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct CompiledMultipleRow - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + public CompiledMultipleRow(MultipleRowDbCommandBuilder commandBuilder) { - readonly MultipleRowDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the struct. - /// - /// The command builder. - public CompiledMultipleRow(MultipleRowDbCommandBuilder commandBuilder) - { - m_CommandBuilder = commandBuilder; - } + m_CommandBuilder = commandBuilder; + } - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The collection options. - /// ILink<List<TObject>>. - public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class, new() - { - return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The collection options. + /// ILink<List<TObject>>. + public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class, new() + { + return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The type of the collection. - /// The collection options. - /// ILink<TCollection>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public ILink ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class, new() - where TCollection : ICollection, new() - { - return new CompiledCollectionMaterializer(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The type of the collection. + /// The collection options. + /// ILink<TCollection>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public ILink ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class, new() + where TCollection : ICollection, new() + { + return new CompiledCollectionMaterializer(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - where TObject : class, new() - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + where TObject : class, new() + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TObject : class, new() - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TObject : class, new() + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`3.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`3.cs index d70bf784c..04b08843f 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleRow`3.cs @@ -2,110 +2,109 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Extension for using compiled materializers with Tortuga Chain +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the result object. +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct CompiledMultipleRow + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class, new() { + readonly MultipleRowDbCommandBuilder m_CommandBuilder; + /// - /// Extension for using compiled materializers with Tortuga Chain + /// Initializes a new instance of the struct. /// - /// The type of the command. - /// The type of the parameter. - /// The type of the result object. - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct CompiledMultipleRow - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class, new() + /// The command builder. + public CompiledMultipleRow(MultipleRowDbCommandBuilder commandBuilder) { - readonly MultipleRowDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the struct. - /// - /// The command builder. - public CompiledMultipleRow(MultipleRowDbCommandBuilder commandBuilder) - { - m_CommandBuilder = commandBuilder; - } + m_CommandBuilder = commandBuilder; + } - /// - /// Materializes the result as a list of objects. - /// - /// The collection options. - /// ILink<List<TObject>>. - public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - { - return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The collection options. + /// ILink<List<TObject>>. + public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + { + return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The collection options. - /// ILink<List<TResultObject>>. - public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TResultObject : class, new() - { - return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The collection options. + /// ILink<List<TResultObject>>. + public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TResultObject : class, new() + { + return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The type of the collection. - /// The collection options. - /// ILink<TCollection>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public ILink ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TResultObject : class, new() - where TCollection : ICollection, new() - { - return new CompiledCollectionMaterializer(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The type of the collection. + /// The collection options. + /// ILink<TCollection>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public ILink ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TResultObject : class, new() + where TCollection : ICollection, new() + { + return new CompiledCollectionMaterializer(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - where TResultObject : class, new() - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + where TResultObject : class, new() + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TResultObject : class, new() - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TResultObject : class, new() + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleTable`2.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleTable`2.cs index e36dabf08..168fae604 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleTable`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledMultipleTable`2.cs @@ -2,78 +2,77 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Extension for using compiled materializers with Tortuga Chain +/// +/// The type of the command. +/// The type of the parameter. +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct CompiledMultipleTable + where TCommand : DbCommand + where TParameter : DbParameter { + readonly MultipleTableDbCommandBuilder m_CommandBuilder; + /// - /// Extension for using compiled materializers with Tortuga Chain + /// Initializes a new instance of the struct. /// - /// The type of the command. - /// The type of the parameter. - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct CompiledMultipleTable - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + public CompiledMultipleTable(MultipleTableDbCommandBuilder commandBuilder) { - readonly MultipleTableDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the struct. - /// - /// The command builder. - public CompiledMultipleTable(MultipleTableDbCommandBuilder commandBuilder) - { - m_CommandBuilder = commandBuilder; - } + m_CommandBuilder = commandBuilder; + } - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The collection options. - /// ILink<List<TObject>>. - public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class, new() - { - return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The collection options. + /// ILink<List<TObject>>. + public ILink> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class, new() + { + return new CompiledCollectionMaterializer>(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The type of the collection. - /// The collection options. - /// ILink<TCollection>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public ILink ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class, new() - where TCollection : ICollection, new() - { - return new CompiledCollectionMaterializer(m_CommandBuilder, collectionOptions); - } + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The type of the collection. + /// The collection options. + /// ILink<TCollection>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public ILink ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class, new() + where TCollection : ICollection, new() + { + return new CompiledCollectionMaterializer(m_CommandBuilder, collectionOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// ILink<TObject>. - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - where TObject : class, new() - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// ILink<TObject>. + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + where TObject : class, new() + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// ILink<TObject>. - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TObject : class, new() - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// ILink<TObject>. + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TObject : class, new() + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectMaterializer`3.cs index fd8aed1e4..4701d46f7 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectMaterializer`3.cs @@ -2,83 +2,82 @@ using Tortuga.Anchor.Metadata; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal sealed class CompiledObjectMaterializer : Materializer + where TCommand : DbCommand + where TObject : class, new() + where TParameter : DbParameter { - internal sealed class CompiledObjectMaterializer : Materializer - where TCommand : DbCommand - where TObject : class, new() - where TParameter : DbParameter + private RowOptions m_RowOptions; + + public CompiledObjectMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) : base(commandBuilder) { - private RowOptions m_RowOptions; + m_RowOptions = rowOptions; - public CompiledObjectMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) : base(commandBuilder) - { - m_RowOptions = rowOptions; + if (rowOptions.HasFlag(RowOptions.InferConstructor)) + throw new NotSupportedException("Compiled materializers do not support non-default constructors"); + } - if (rowOptions.HasFlag(RowOptions.InferConstructor)) - throw new NotSupportedException("Compiled materializers do not support non-default constructors"); - } + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + public override IReadOnlyList DesiredColumns() => MetadataCache.GetMetadata(typeof(TObject)).ColumnsFor; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - public override IReadOnlyList DesiredColumns() => MetadataCache.GetMetadata(typeof(TObject)).ColumnsFor; + public override TObject Execute(object? state = null) + { + var result = new List(); - public override TObject Execute(object? state = null) + var executionToken = Prepare(); + executionToken.Execute(cmd => { - var result = new List(); - - var executionToken = Prepare(); - executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); - while (reader.Read()) - result.Add(factory(reader)); - return result.Count; - } - }, state); - - if (result.Count == 0) - { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToObjectOrNull` instead of `.ToObject`."); - } - else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); + while (reader.Read()) + result.Add(factory(reader)); + return result.Count; } + }, state); - return result.First(); + if (result.Count == 0) + { + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToObjectOrNull` instead of `.ToObject`."); } - - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) { - var result = new List(); + throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + } - var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => - { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); - while (await reader.ReadAsync().ConfigureAwait(false)) - result.Add(factory(reader)); - return result.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + return result.First(); + } - if (result.Count == 0) - { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToObjectOrNull` instead of `.ToObject`."); - } - else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); + + var executionToken = Prepare(); + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); + while (await reader.ReadAsync().ConfigureAwait(false)) + result.Add(factory(reader)); + return result.Count; } + }, cancellationToken, state).ConfigureAwait(false); - return result.First(); + if (result.Count == 0) + { + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToObjectOrNull` instead of `.ToObject`."); } + else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + } + + return result.First(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectOrNullMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectOrNullMaterializer`3.cs index 20ae356d6..6b010a88e 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectOrNullMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledObjectOrNullMaterializer`3.cs @@ -2,89 +2,88 @@ using Tortuga.Anchor.Metadata; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal sealed class CompiledObjectOrNullMaterializer : Materializer +where TCommand : DbCommand +where TObject : class, new() +where TParameter : DbParameter { - internal sealed class CompiledObjectOrNullMaterializer : Materializer - where TCommand : DbCommand - where TObject : class, new() - where TParameter : DbParameter + private RowOptions m_RowOptions; + + public CompiledObjectOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) : base(commandBuilder) { - private RowOptions m_RowOptions; + m_RowOptions = rowOptions; - public CompiledObjectOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) : base(commandBuilder) - { - m_RowOptions = rowOptions; + if (rowOptions.HasFlag(RowOptions.InferConstructor)) + throw new NotSupportedException("Compiled materializers do not support non-default constructors"); + } - if (rowOptions.HasFlag(RowOptions.InferConstructor)) - throw new NotSupportedException("Compiled materializers do not support non-default constructors"); - } + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + public override IReadOnlyList DesiredColumns() => MetadataCache.GetMetadata(typeof(TObject)).ColumnsFor; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - public override IReadOnlyList DesiredColumns() => MetadataCache.GetMetadata(typeof(TObject)).ColumnsFor; + public override TObject? Execute(object? state = null) + { + var result = new List(); - public override TObject? Execute(object? state = null) + var executionToken = Prepare(); + executionToken.Execute(cmd => { - var result = new List(); - - var executionToken = Prepare(); - executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); - while (reader.Read()) - result.Add(factory(reader)); - return result.Count; - } - }, state); - - if (result.Count == 0) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); + while (reader.Read()) + result.Add(factory(reader)); + return result.Count; } + }, state); - return result.First(); + if (result.Count == 0) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); } - - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) { - var result = new List(); + throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + } - var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => - { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); - while (await reader.ReadAsync().ConfigureAwait(false)) - result.Add(factory(reader)); - return result.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + return result.First(); + } - if (result.Count == 0) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); + + var executionToken = Prepare(); + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + var factory = CompiledMaterializers.CreateBuilder(DataSource, cmd.CommandText, reader, CommandBuilder.TryGetNonNullableColumns()); + while (await reader.ReadAsync().ConfigureAwait(false)) + result.Add(factory(reader)); + return result.Count; } + }, cancellationToken, state).ConfigureAwait(false); - return result.First(); + if (result.Count == 0) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); } + else if (result.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException($"Expected 1 row but received {result.Count} rows. Use {nameof(RowOptions)}.{nameof(RowOptions.DiscardExtraRows)} to suppress this error."); + } + + return result.First(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`2.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`2.cs index df119af0c..892a0738a 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`2.cs @@ -2,51 +2,50 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Extension for using compiled materializers with Tortuga Chain +/// +/// The type of the command. +/// The type of the parameter. +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct CompiledSingleRow + where TCommand : DbCommand + where TParameter : DbParameter { + readonly SingleRowDbCommandBuilder m_CommandBuilder; + /// - /// Extension for using compiled materializers with Tortuga Chain + /// Initializes a new instance of the struct. /// - /// The type of the command. - /// The type of the parameter. - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct CompiledSingleRow - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + public CompiledSingleRow(SingleRowDbCommandBuilder commandBuilder) { - readonly SingleRowDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the struct. - /// - /// The command builder. - public CompiledSingleRow(SingleRowDbCommandBuilder commandBuilder) - { - m_CommandBuilder = commandBuilder; - } + m_CommandBuilder = commandBuilder; + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - where TObject : class, new() - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + where TObject : class, new() + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TObject : class, new() - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TObject : class, new() + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`3.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`3.cs index 9a9884f04..f9e26a887 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompiledSingleRow`3.cs @@ -2,73 +2,72 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Extension for using compiled materializers with Tortuga Chain +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the result object. +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct CompiledSingleRow + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class, new() { + readonly SingleRowDbCommandBuilder m_CommandBuilder; + /// - /// Extension for using compiled materializers with Tortuga Chain + /// Initializes a new instance of the struct. /// - /// The type of the command. - /// The type of the parameter. - /// The type of the result object. - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct CompiledSingleRow - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class, new() + /// The command builder. + public CompiledSingleRow(SingleRowDbCommandBuilder commandBuilder) { - readonly SingleRowDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the struct. - /// - /// The command builder. - public CompiledSingleRow(SingleRowDbCommandBuilder commandBuilder) - { - m_CommandBuilder = commandBuilder; - } + m_CommandBuilder = commandBuilder; + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + where TResultObject : class, new() + { + return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - where TResultObject : class, new() - { - return new CompiledObjectMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TResultObject : class, new() - { - return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TResultObject : class, new() + { + return new CompiledObjectOrNullMaterializer(m_CommandBuilder, rowOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompilerCache.cs b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompilerCache.cs index f40bca4e7..18e8039cb 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompilerCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Materializers/CompilerCache.cs @@ -1,24 +1,23 @@ using CSScriptLib; using System.Collections.Concurrent; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal class CompilerCache { - internal class CompilerCache - { - readonly ConcurrentDictionary> m_Cache = new ConcurrentDictionary>(); + readonly ConcurrentDictionary> m_Cache = new ConcurrentDictionary>(); - public MethodDelegate? GetBuilder(string sql) - where TObject : new() - { - var cache2 = m_Cache.GetOrAdd(typeof(TObject), x => new ConcurrentDictionary()); - cache2.TryGetValue(sql, out var result); - return (MethodDelegate?)result; - } + public MethodDelegate? GetBuilder(string sql) + where TObject : new() + { + var cache2 = m_Cache.GetOrAdd(typeof(TObject), x => new ConcurrentDictionary()); + cache2.TryGetValue(sql, out var result); + return (MethodDelegate?)result; + } - internal void StoreBuilder(string sql, MethodDelegate builder) where TObject : new() - { - var cache2 = m_Cache.GetOrAdd(typeof(TObject), x => new ConcurrentDictionary()); - cache2.TryAdd(sql, builder); - } + internal void StoreBuilder(string sql, MethodDelegate builder) where TObject : new() + { + var cache2 = m_Cache.GetOrAdd(typeof(TObject), x => new ConcurrentDictionary()); + cache2.TryAdd(sql, builder); } } diff --git a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Tortuga.Chain.CompiledMaterializers.csproj b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Tortuga.Chain.CompiledMaterializers.csproj index 277d90492..2b4222d18 100644 --- a/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Tortuga.Chain.CompiledMaterializers.csproj +++ b/Tortuga.Chain/Tortuga.Chain.CompiledMaterializers/Tortuga.Chain.CompiledMaterializers.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.0 + 4.1.0 MIT @@ -39,7 +39,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.Core.Odbc/OdbcDatabaseMetadataCache`1.cs b/Tortuga.Chain/Tortuga.Chain.Core.Odbc/OdbcDatabaseMetadataCache`1.cs index f3582935a..118caa7f3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core.Odbc/OdbcDatabaseMetadataCache`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core.Odbc/OdbcDatabaseMetadataCache`1.cs @@ -1,87 +1,86 @@ using System.Data.Odbc; using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Meatadata cache base class for ODBC databases +/// +/// The type used to represent database object names. +public abstract class OdbcDatabaseMetadataCache : DatabaseMetadataCache + where TObjectName : struct { /// - /// Meatadata cache base class for ODBC databases + /// Returns the CLR type that matches the indicated database column type. /// - /// The type used to represent database object names. - public abstract class OdbcDatabaseMetadataCache : DatabaseMetadataCache - where TObjectName : struct + /// Type of the database column. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. Defaults to string. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// + /// This does not take into consideration registered types. + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502")] + protected override Type? ToClrType(OdbcType dbType, bool isNullable, int? maxLength) { - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Type of the database column. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. Defaults to string. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// - /// This does not take into consideration registered types. - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - protected override Type? ToClrType(OdbcType dbType, bool isNullable, int? maxLength) + switch (dbType) { - switch (dbType) - { - case OdbcType.BigInt: - return isNullable ? typeof(long?) : typeof(long); + case OdbcType.BigInt: + return isNullable ? typeof(long?) : typeof(long); - case OdbcType.Binary: - return typeof(byte[]); + case OdbcType.Binary: + return typeof(byte[]); - case OdbcType.Bit: - return isNullable ? typeof(bool?) : typeof(bool); + case OdbcType.Bit: + return isNullable ? typeof(bool?) : typeof(bool); - case OdbcType.NChar: - case OdbcType.NVarChar: - case OdbcType.Char: - case OdbcType.VarChar: - return (maxLength == 1) ? - (isNullable ? typeof(char?) : typeof(char)) - : typeof(string); + case OdbcType.NChar: + case OdbcType.NVarChar: + case OdbcType.Char: + case OdbcType.VarChar: + return (maxLength == 1) ? + (isNullable ? typeof(char?) : typeof(char)) + : typeof(string); - case OdbcType.Decimal: - case OdbcType.Numeric: - return isNullable ? typeof(decimal?) : typeof(decimal); + case OdbcType.Decimal: + case OdbcType.Numeric: + return isNullable ? typeof(decimal?) : typeof(decimal); - case OdbcType.Double: - return isNullable ? typeof(double?) : typeof(double); + case OdbcType.Double: + return isNullable ? typeof(double?) : typeof(double); - case OdbcType.Int: - return isNullable ? typeof(int?) : typeof(int); + case OdbcType.Int: + return isNullable ? typeof(int?) : typeof(int); - case OdbcType.Text: - case OdbcType.NText: - return typeof(string); + case OdbcType.Text: + case OdbcType.NText: + return typeof(string); - case OdbcType.Real: - return isNullable ? typeof(float?) : typeof(float); + case OdbcType.Real: + return isNullable ? typeof(float?) : typeof(float); - case OdbcType.UniqueIdentifier: - return isNullable ? typeof(Guid?) : typeof(Guid); + case OdbcType.UniqueIdentifier: + return isNullable ? typeof(Guid?) : typeof(Guid); - case OdbcType.SmallInt: - return isNullable ? typeof(ushort?) : typeof(ushort); + case OdbcType.SmallInt: + return isNullable ? typeof(ushort?) : typeof(ushort); - case OdbcType.TinyInt: - return isNullable ? typeof(byte?) : typeof(byte); + case OdbcType.TinyInt: + return isNullable ? typeof(byte?) : typeof(byte); - case OdbcType.VarBinary: - case OdbcType.Image: - case OdbcType.Timestamp: - return typeof(byte[]); + case OdbcType.VarBinary: + case OdbcType.Image: + case OdbcType.Timestamp: + return typeof(byte[]); - case OdbcType.Date: - case OdbcType.DateTime: - case OdbcType.SmallDateTime: - case OdbcType.Time: - return typeof(DateTime); - } - return null; + case OdbcType.Date: + case OdbcType.DateTime: + case OdbcType.SmallDateTime: + case OdbcType.Time: + return typeof(DateTime); } + return null; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core.Odbc/Tortuga.Chain.Core.Odbc.csproj b/Tortuga.Chain/Tortuga.Chain.Core.Odbc/Tortuga.Chain.Core.Odbc.csproj index 1ebdba2e5..ad0e9d662 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core.Odbc/Tortuga.Chain.Core.Odbc.csproj +++ b/Tortuga.Chain/Tortuga.Chain.Core.Odbc/Tortuga.Chain.Core.Odbc.csproj @@ -11,7 +11,7 @@ Tortuga Chain true - 4.0.0 + 4.1.0 MIT @@ -52,7 +52,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Metadata/OleDbDatabaseMetadataCache`1.cs b/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Metadata/OleDbDatabaseMetadataCache`1.cs index c9f0f92a2..5330cbfdb 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Metadata/OleDbDatabaseMetadataCache`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Metadata/OleDbDatabaseMetadataCache`1.cs @@ -109,4 +109,4 @@ public abstract class OleDbDatabaseMetadataCache : DatabaseMetadata return null; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Tortuga.Chain.Core.OleDb.csproj b/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Tortuga.Chain.Core.OleDb.csproj index 54d724739..5ef54d35f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Tortuga.Chain.Core.OleDb.csproj +++ b/Tortuga.Chain/Tortuga.Chain.Core.OleDb/Tortuga.Chain.Core.OleDb.csproj @@ -11,7 +11,7 @@ Tortuga Chain true - 4.0.0 + 4.1.0 MIT @@ -46,7 +46,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AbortableOperationEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.Core/AbortableOperationEventArgs.cs index 233b04320..b110c5f32 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AbortableOperationEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AbortableOperationEventArgs.cs @@ -1,25 +1,24 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Represents a notification from an abortable process such as a bulk insert. +/// +public class AbortableOperationEventArgs : EventArgs { /// - /// Represents a notification from an abortable process such as a bulk insert. + /// Initializes a new instance of the class. /// - public class AbortableOperationEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// The number of rows affected. - public AbortableOperationEventArgs(long rowsAffected) { RowsAffected = rowsAffected; } + /// The number of rows affected. + public AbortableOperationEventArgs(long rowsAffected) { RowsAffected = rowsAffected; } - /// - /// Gets or sets a value indicating whether this is abort. - /// - /// Set to True to abort the current operation. - public bool Abort { get; set; } + /// + /// Gets or sets a value indicating whether this is abort. + /// + /// Set to True to abort the current operation. + public bool Abort { get; set; } - /// - /// Gets the number of rows copied. - /// - public long RowsAffected { get; } - } + /// + /// Gets the number of rows copied. + /// + public long RowsAffected { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`1.cs index ecc589f20..0d1eed209 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`1.cs @@ -1,114 +1,113 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// An appender modifies the execution chain of an operation, usually by performing an action just before or after the database call. +/// +/// The operation's result type. +public abstract class Appender : ILink { /// - /// An appender modifies the execution chain of an operation, usually by performing an action just before or after the database call. + /// Initializes a new instance of the class. + /// + /// The previous link. + /// previousLink + protected Appender(ILink previousLink) + { + PreviousLink = previousLink ?? throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); + PreviousLink.ExecutionTokenPrepared += PreviousLink_ExecutionTokenPrepared; + PreviousLink.ExecutionTokenPreparing += PreviousLink_ExecutionTokenPreparing; + } + + /// + /// Occurs when an execution token has been prepared. + /// + /// This is mostly used by appenders to override command behavior. + public event EventHandler? ExecutionTokenPrepared; + + /// + /// Occurs when an execution token is about to be prepared. + /// + /// + /// This is mostly used by appenders to override SQL generation. + /// + public event EventHandler? ExecutionTokenPreparing; + + /// + /// Gets the data source that is associated with this materializer or appender. + /// + /// The data source. + public IDataSource DataSource => PreviousLink.DataSource; + + /// + /// Gets the previous link in the operation chain. /// - /// The operation's result type. - public abstract class Appender : ILink + public ILink PreviousLink { get; } + + /// + /// Returns the generated SQL statement of the previous link. + /// + /// + public string? CommandText() => PreviousLink.CommandText(); + + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// If you don't override this method, it will call execute on the previous link. + public virtual TResult Execute(object? state = null) => PreviousLink.Execute(state); + + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// + public Task ExecuteAsync(object? state = null) => ExecuteAsync(CancellationToken.None, state); + + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// If you don't override this method, it will call execute on the previous link. + public virtual Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + return PreviousLink.ExecuteAsync(cancellationToken, state); + } + + /// + /// Override this if you want to examine or modify the DBCommand before it is executed. + /// + /// The instance containing the event data. + protected virtual void OnCommandBuilt(CommandBuiltEventArgs e) { } + + /// + /// Override this if you want to examine or modify the execution token before the DBCommand object is built. + /// + /// The instance containing the event data. + protected virtual void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) { } + + /// + /// Override this if you want to examine or modify the command builder before the execution token is built. + /// + /// The instance containing the event data. + protected virtual void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) { } + + void ExecutionToken_CommandBuilt(object? sender, CommandBuiltEventArgs e) => OnCommandBuilt(e); + + void PreviousLink_ExecutionTokenPrepared(object? sender, ExecutionTokenPreparedEventArgs e) + { + OnExecutionTokenPrepared(e); //left first + ExecutionTokenPrepared?.Invoke(this, e); //then right + e.ExecutionToken.CommandBuilt += ExecutionToken_CommandBuilt; + } + + void PreviousLink_ExecutionTokenPreparing(object? sender, ExecutionTokenPreparingEventArgs e) { - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// previousLink - protected Appender(ILink previousLink) - { - PreviousLink = previousLink ?? throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); - PreviousLink.ExecutionTokenPrepared += PreviousLink_ExecutionTokenPrepared; - PreviousLink.ExecutionTokenPreparing += PreviousLink_ExecutionTokenPreparing; - } - - /// - /// Occurs when an execution token has been prepared. - /// - /// This is mostly used by appenders to override command behavior. - public event EventHandler? ExecutionTokenPrepared; - - /// - /// Occurs when an execution token is about to be prepared. - /// - /// - /// This is mostly used by appenders to override SQL generation. - /// - public event EventHandler? ExecutionTokenPreparing; - - /// - /// Gets the data source that is associated with this materializer or appender. - /// - /// The data source. - public IDataSource DataSource => PreviousLink.DataSource; - - /// - /// Gets the previous link in the operation chain. - /// - public ILink PreviousLink { get; } - - /// - /// Returns the generated SQL statement of the previous link. - /// - /// - public string? CommandText() => PreviousLink.CommandText(); - - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// If you don't override this method, it will call execute on the previous link. - public virtual TResult Execute(object? state = null) => PreviousLink.Execute(state); - - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// - public Task ExecuteAsync(object? state = null) => ExecuteAsync(CancellationToken.None, state); - - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// If you don't override this method, it will call execute on the previous link. - public virtual Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - return PreviousLink.ExecuteAsync(cancellationToken, state); - } - - /// - /// Override this if you want to examine or modify the DBCommand before it is executed. - /// - /// The instance containing the event data. - protected virtual void OnCommandBuilt(CommandBuiltEventArgs e) { } - - /// - /// Override this if you want to examine or modify the execution token before the DBCommand object is built. - /// - /// The instance containing the event data. - protected virtual void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) { } - - /// - /// Override this if you want to examine or modify the command builder before the execution token is built. - /// - /// The instance containing the event data. - protected virtual void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) { } - - void ExecutionToken_CommandBuilt(object? sender, CommandBuiltEventArgs e) => OnCommandBuilt(e); - - void PreviousLink_ExecutionTokenPrepared(object? sender, ExecutionTokenPreparedEventArgs e) - { - OnExecutionTokenPrepared(e); //left first - ExecutionTokenPrepared?.Invoke(this, e); //then right - e.ExecutionToken.CommandBuilt += ExecutionToken_CommandBuilt; - } - - void PreviousLink_ExecutionTokenPreparing(object? sender, ExecutionTokenPreparingEventArgs e) - { - OnExecutionTokenPreparing(e); //left first - ExecutionTokenPreparing?.Invoke(this, e); //then right - } + OnExecutionTokenPreparing(e); //left first + ExecutionTokenPreparing?.Invoke(this, e); //then right } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`2.cs index ec16ad203..c57a6cc12 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/Appender`2.cs @@ -1,125 +1,124 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// An appender modifies the execution chain of an operation, usually by performing an action just before or after the database call. This version can convert an ILink from one type to another. +/// +/// The type of the input type. +/// The type of the output type. +/// +public abstract class Appender : ILink { /// - /// An appender modifies the execution chain of an operation, usually by performing an action just before or after the database call. This version can convert an ILink from one type to another. + /// Initializes a new instance of the class. + /// + /// The previous link. + /// previousLink;previousLink is null. + protected Appender(ILink previousLink) + { + PreviousLink = previousLink ?? throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); + PreviousLink.ExecutionTokenPrepared += PreviousLink_ExecutionTokenPrepared; + PreviousLink.ExecutionTokenPreparing += PreviousLink_ExecutionTokenPreparing; + } + + /// + /// Occurs when an execution token has been prepared. + /// + /// This is mostly used by appenders to override command behavior. + public event EventHandler? ExecutionTokenPrepared; + + /// + /// Occurs when an execution token is about to be prepared. + /// + /// + /// This is mostly used by appenders to override SQL generation. + /// + public event EventHandler? ExecutionTokenPreparing; + + /// + /// Gets the data source that is associated with this materializer or appender. + /// + /// The data source. + public IDataSource DataSource => PreviousLink.DataSource; + + /// + /// Gets the previous link in the operation chain. /// - /// The type of the input type. - /// The type of the output type. - /// - public abstract class Appender : ILink + public ILink PreviousLink { get; } + + /// + /// Returns the generated SQL statement of the previous link. + /// + /// + public string? CommandText() => PreviousLink.CommandText(); + + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// If you don't override this method, it will call execute on the previous link. + public abstract TOut Execute(object? state = null); + + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// + public Task ExecuteAsync(object? state = null) + { + return ExecuteAsync(CancellationToken.None, state); + } + + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// If you don't override this method, it will call execute on the previous link. + public abstract Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); + + /// + /// Override this if you want to examine or modify the DBCommand before it is executed. + /// + /// The instance containing the event data. + protected virtual void OnCommandBuilt(CommandBuiltEventArgs e) + { + } + + /// + /// Override this if you want to examine or modify the execution token before the DBCommand object is built. + /// + /// The instance containing the event data. + protected virtual void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) + { + } + + /// + /// Override this if you want to examine or modify the command builder before the execution token is built. + /// + /// The instance containing the event data. + protected virtual void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) + { + } + + void ExecutionToken_CommandBuilt(object? sender, CommandBuiltEventArgs e) + { + OnCommandBuilt(e); + } + + void PreviousLink_ExecutionTokenPrepared(object? sender, ExecutionTokenPreparedEventArgs e) + { + OnExecutionTokenPrepared(e); //left first + ExecutionTokenPrepared?.Invoke(this, e); //then right + e.ExecutionToken.CommandBuilt += ExecutionToken_CommandBuilt; + } + + void PreviousLink_ExecutionTokenPreparing(object? sender, ExecutionTokenPreparingEventArgs e) { - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// previousLink;previousLink is null. - protected Appender(ILink previousLink) - { - PreviousLink = previousLink ?? throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); - PreviousLink.ExecutionTokenPrepared += PreviousLink_ExecutionTokenPrepared; - PreviousLink.ExecutionTokenPreparing += PreviousLink_ExecutionTokenPreparing; - } - - /// - /// Occurs when an execution token has been prepared. - /// - /// This is mostly used by appenders to override command behavior. - public event EventHandler? ExecutionTokenPrepared; - - /// - /// Occurs when an execution token is about to be prepared. - /// - /// - /// This is mostly used by appenders to override SQL generation. - /// - public event EventHandler? ExecutionTokenPreparing; - - /// - /// Gets the data source that is associated with this materializer or appender. - /// - /// The data source. - public IDataSource DataSource => PreviousLink.DataSource; - - /// - /// Gets the previous link in the operation chain. - /// - public ILink PreviousLink { get; } - - /// - /// Returns the generated SQL statement of the previous link. - /// - /// - public string? CommandText() => PreviousLink.CommandText(); - - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// If you don't override this method, it will call execute on the previous link. - public abstract TOut Execute(object? state = null); - - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// - public Task ExecuteAsync(object? state = null) - { - return ExecuteAsync(CancellationToken.None, state); - } - - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// If you don't override this method, it will call execute on the previous link. - public abstract Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); - - /// - /// Override this if you want to examine or modify the DBCommand before it is executed. - /// - /// The instance containing the event data. - protected virtual void OnCommandBuilt(CommandBuiltEventArgs e) - { - } - - /// - /// Override this if you want to examine or modify the execution token before the DBCommand object is built. - /// - /// The instance containing the event data. - protected virtual void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) - { - } - - /// - /// Override this if you want to examine or modify the command builder before the execution token is built. - /// - /// The instance containing the event data. - protected virtual void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) - { - } - - void ExecutionToken_CommandBuilt(object? sender, CommandBuiltEventArgs e) - { - OnCommandBuilt(e); - } - - void PreviousLink_ExecutionTokenPrepared(object? sender, ExecutionTokenPreparedEventArgs e) - { - OnExecutionTokenPrepared(e); //left first - ExecutionTokenPrepared?.Invoke(this, e); //then right - e.ExecutionToken.CommandBuilt += ExecutionToken_CommandBuilt; - } - - void PreviousLink_ExecutionTokenPreparing(object? sender, ExecutionTokenPreparingEventArgs e) - { - OnExecutionTokenPreparing(e); //left first - ExecutionTokenPreparing?.Invoke(this, e); //then right - } + OnExecutionTokenPreparing(e); //left first + ExecutionTokenPreparing?.Invoke(this, e); //then right } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheAllItemsAppender.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheAllItemsAppender.cs index b2d0e28b9..4240689de 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheAllItemsAppender.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheAllItemsAppender.cs @@ -1,85 +1,84 @@ using System.Collections.Immutable; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Caches each individual item in the collection. +/// Implements the +/// Implements the +/// +/// The type of the t collection. +/// The type of the t item. +/// +/// +/// This operation will not read from the cache. +internal sealed class CacheAllItemsAppender : Appender, ICacheLink + where TCollection : IEnumerable { + readonly Func m_CacheKeyFunction; + readonly CachePolicy? m_Policy; + + ImmutableArray m_ActualCacheKeys; + /// - /// Caches each individual item in the collection. - /// Implements the - /// Implements the + /// Initializes a new instance of the class. /// - /// The type of the t collection. - /// The type of the t item. - /// - /// - /// This operation will not read from the cache. - internal sealed class CacheAllItemsAppender : Appender, ICacheLink - where TCollection : IEnumerable + /// The previous link. + /// Function to generate cache keys. + /// Optional cache policy. + /// previousLink;previousLink is null. + /// cacheKey is null or empty.;cacheKey + public CacheAllItemsAppender(ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) : base(previousLink) { - readonly Func m_CacheKeyFunction; - readonly CachePolicy? m_Policy; + m_CacheKeyFunction = cacheKeyFunction ?? throw new ArgumentNullException(nameof(cacheKeyFunction), $"{nameof(cacheKeyFunction)} is null."); + m_Policy = policy; + } - ImmutableArray m_ActualCacheKeys; + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + public override TCollection Execute(object? state = null) + { + var result = PreviousLink.Execute(state); - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// Function to generate cache keys. - /// Optional cache policy. - /// previousLink;previousLink is null. - /// cacheKey is null or empty.;cacheKey - public CacheAllItemsAppender(ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) : base(previousLink) - { - m_CacheKeyFunction = cacheKeyFunction ?? throw new ArgumentNullException(nameof(cacheKeyFunction), $"{nameof(cacheKeyFunction)} is null."); - m_Policy = policy; - } + var cacheKeys = new List(); - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - public override TCollection Execute(object? state = null) + foreach (var item in result) { - var result = PreviousLink.Execute(state); - - var cacheKeys = new List(); - - foreach (var item in result) - { - var cacheKey = m_CacheKeyFunction(item); - DataSource.Cache.Write(cacheKey, item, m_Policy); - cacheKeys.Add(cacheKey); - } - - m_ActualCacheKeys = cacheKeys.ToImmutableArray(); - return result; + var cacheKey = m_CacheKeyFunction(item); + DataSource.Cache.Write(cacheKey, item, m_Policy); + cacheKeys.Add(cacheKey); } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); + m_ActualCacheKeys = cacheKeys.ToImmutableArray(); + return result; + } - var cacheKeys = new List(); - foreach (var item in result) - { - var cacheKey = m_CacheKeyFunction(item); - await DataSource.Cache.WriteAsync(cacheKey, item, m_Policy).ConfigureAwait(false); - cacheKeys.Add(cacheKey); - } - m_ActualCacheKeys = cacheKeys.ToImmutableArray(); - return result; - } + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); - void ICacheLink.Invalidate() + var cacheKeys = new List(); + foreach (var item in result) { - foreach (var cacheKey in m_ActualCacheKeys) - DataSource.Cache.Invalidate(cacheKey); + var cacheKey = m_CacheKeyFunction(item); + await DataSource.Cache.WriteAsync(cacheKey, item, m_Policy).ConfigureAwait(false); + cacheKeys.Add(cacheKey); } + m_ActualCacheKeys = cacheKeys.ToImmutableArray(); + return result; + } + + void ICacheLink.Invalidate() + { + foreach (var cacheKey in m_ActualCacheKeys) + DataSource.Cache.Invalidate(cacheKey); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheResultAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheResultAppender`1.cs index 13da726f9..d6e939648 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheResultAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/CacheResultAppender`1.cs @@ -1,80 +1,79 @@ -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Executes the previous link and caches the result. +/// +/// The type of the t result type. +internal sealed class CacheResultAppender : Appender, ICacheLink { + readonly string? m_CacheKey; + readonly Func? m_CacheKeyFunction; + readonly CachePolicy? m_Policy; + string? m_ActualCacheKey; + /// - /// Executes the previous link and caches the result. + /// Initializes a new instance of the class. /// - /// The type of the t result type. - internal sealed class CacheResultAppender : Appender, ICacheLink + /// The previous link. + /// Function to generate cache keys. + /// Optional cache policy. + /// cacheKeyFunction + public CacheResultAppender(ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) : base(previousLink) { - readonly string? m_CacheKey; - readonly Func? m_CacheKeyFunction; - readonly CachePolicy? m_Policy; - string? m_ActualCacheKey; - - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// Function to generate cache keys. - /// Optional cache policy. - /// cacheKeyFunction - public CacheResultAppender(ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) : base(previousLink) - { - m_CacheKeyFunction = cacheKeyFunction ?? throw new ArgumentNullException(nameof(cacheKeyFunction), $"{nameof(cacheKeyFunction)} is null."); - m_Policy = policy; - } + m_CacheKeyFunction = cacheKeyFunction ?? throw new ArgumentNullException(nameof(cacheKeyFunction), $"{nameof(cacheKeyFunction)} is null."); + m_Policy = policy; + } - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// The cache key. - /// Optional cache policy. - public CacheResultAppender(ILink previousLink, string cacheKey, CachePolicy? policy) : base(previousLink) - { - if (previousLink == null) - throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); + /// + /// Initializes a new instance of the class. + /// + /// The previous link. + /// The cache key. + /// Optional cache policy. + public CacheResultAppender(ILink previousLink, string cacheKey, CachePolicy? policy) : base(previousLink) + { + if (previousLink == null) + throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - m_Policy = policy; - m_CacheKey = cacheKey; - } + m_Policy = policy; + m_CacheKey = cacheKey; + } - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - public override TResult Execute(object? state = null) - { - var result = PreviousLink.Execute(state); + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + public override TResult Execute(object? state = null) + { + var result = PreviousLink.Execute(state); - m_ActualCacheKey = m_CacheKey ?? m_CacheKeyFunction!(result); - DataSource.Cache.Write(m_ActualCacheKey, result, m_Policy); + m_ActualCacheKey = m_CacheKey ?? m_CacheKeyFunction!(result); + DataSource.Cache.Write(m_ActualCacheKey, result, m_Policy); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); - m_ActualCacheKey = m_CacheKey ?? m_CacheKeyFunction!(result); - await DataSource.Cache.WriteAsync(m_ActualCacheKey, result, m_Policy).ConfigureAwait(false); + m_ActualCacheKey = m_CacheKey ?? m_CacheKeyFunction!(result); + await DataSource.Cache.WriteAsync(m_ActualCacheKey, result, m_Policy).ConfigureAwait(false); - return result; - } + return result; + } - void ICacheLink.Invalidate() - { - if (m_ActualCacheKey != null) - DataSource.Cache.Invalidate(m_ActualCacheKey); - } + void ICacheLink.Invalidate() + { + if (m_ActualCacheKey != null) + DataSource.Cache.Invalidate(m_ActualCacheKey); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ExpressionJoinAppender`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ExpressionJoinAppender`2.cs index e8b55cbd7..a8511f43f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ExpressionJoinAppender`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ExpressionJoinAppender`2.cs @@ -1,73 +1,72 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +internal sealed class ExpressionJoinAppender : Appender, List>, List> { - internal sealed class ExpressionJoinAppender : Appender, List>, List> - { - readonly Func m_JoinExpression; - readonly JoinOptions m_JoinOptions; - readonly Func> m_TargetCollectionExpression; + readonly Func m_JoinExpression; + readonly JoinOptions m_JoinOptions; + readonly Func> m_TargetCollectionExpression; - public ExpressionJoinAppender(ILink, List>> previousLink, Func joinExpression, Func> targetCollectionExpression, JoinOptions joinOptions) : base(previousLink) - { - m_TargetCollectionExpression = targetCollectionExpression ?? throw new ArgumentNullException(nameof(targetCollectionExpression), $"{nameof(targetCollectionExpression)} is null."); - m_JoinOptions = joinOptions; - m_JoinExpression = joinExpression ?? throw new ArgumentNullException(nameof(joinExpression), $"{nameof(joinExpression)} is null."); - } + public ExpressionJoinAppender(ILink, List>> previousLink, Func joinExpression, Func> targetCollectionExpression, JoinOptions joinOptions) : base(previousLink) + { + m_TargetCollectionExpression = targetCollectionExpression ?? throw new ArgumentNullException(nameof(targetCollectionExpression), $"{nameof(targetCollectionExpression)} is null."); + m_JoinOptions = joinOptions; + m_JoinExpression = joinExpression ?? throw new ArgumentNullException(nameof(joinExpression), $"{nameof(joinExpression)} is null."); + } - public ExpressionJoinAppender(ILink, List>> previousLink, Func joinExpression, string targetCollectionName, JoinOptions joinOptions) : base(previousLink) - { - if (previousLink == null) - throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); + public ExpressionJoinAppender(ILink, List>> previousLink, Func joinExpression, string targetCollectionName, JoinOptions joinOptions) : base(previousLink) + { + if (previousLink == null) + throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); - if (string.IsNullOrEmpty(targetCollectionName)) - throw new ArgumentException($"{nameof(targetCollectionName)} is null or empty.", nameof(targetCollectionName)); + if (string.IsNullOrEmpty(targetCollectionName)) + throw new ArgumentException($"{nameof(targetCollectionName)} is null or empty.", nameof(targetCollectionName)); - var targetPropertyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[targetCollectionName]; //don't inline this variable. - m_TargetCollectionExpression = (p) => (ICollection)(targetPropertyStub.InvokeGet(p!) ?? $"{targetCollectionName} is null. Expected a non-null collection."); + var targetPropertyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[targetCollectionName]; //don't inline this variable. + m_TargetCollectionExpression = (p) => (ICollection)(targetPropertyStub.InvokeGet(p!) ?? $"{targetCollectionName} is null. Expected a non-null collection."); - m_JoinOptions = joinOptions; - m_JoinExpression = joinExpression ?? throw new ArgumentNullException(nameof(joinExpression), $"{nameof(joinExpression)} is null."); - } + m_JoinOptions = joinOptions; + m_JoinExpression = joinExpression ?? throw new ArgumentNullException(nameof(joinExpression), $"{nameof(joinExpression)} is null."); + } - public override List Execute(object? state = null) - { - var result = PreviousLink.Execute(state); - Match(result); - return result.Item1; - } + public override List Execute(object? state = null) + { + var result = PreviousLink.Execute(state); + Match(result); + return result.Item1; + } - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); - Match(result); - return result.Item1; - } + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); + Match(result); + return result.Item1; + } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] - void Match(Tuple, List> result) + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] + void Match(Tuple, List> result) + { + foreach (var child in result.Item2) { - foreach (var child in result.Item2) + var matched = false; + foreach (var parent in result.Item1) { - var matched = false; - foreach (var parent in result.Item1) - { - if (m_JoinExpression(parent, child)) - { - matched = true; - m_TargetCollectionExpression(parent).Add(child); - if (!m_JoinOptions.HasFlag(JoinOptions.MultipleParents)) - break; - } - } - if (!matched && !m_JoinOptions.HasFlag(JoinOptions.IgnoreUnmatchedChildren)) + if (m_JoinExpression(parent, child)) { - var ex = new UnexpectedDataException("Found child object that couldn't be matched to a parent. See Exception.Data[\"ChildObject\"] for details."); - ex.Data["ChildObject"] = child; - throw ex; + matched = true; + m_TargetCollectionExpression(parent).Add(child); + if (!m_JoinOptions.HasFlag(JoinOptions.MultipleParents)) + break; } } + if (!matched && !m_JoinOptions.HasFlag(JoinOptions.IgnoreUnmatchedChildren)) + { + var ex = new UnexpectedDataException("Found child object that couldn't be matched to a parent. See Exception.Data[\"ChildObject\"] for details."); + ex.Data["ChildObject"] = child; + throw ex; + } } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/InvalidateCacheAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/InvalidateCacheAppender`1.cs index d7c1ff740..d77374e22 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/InvalidateCacheAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/InvalidateCacheAppender`1.cs @@ -1,50 +1,49 @@ -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Causes the cache to be invalidated when this operation is executed. +/// +/// +internal sealed class InvalidateCacheAppender : Appender { + readonly string m_CacheKey; + /// - /// Causes the cache to be invalidated when this operation is executed. + /// Initializes a new instance of the class. /// - /// - internal sealed class InvalidateCacheAppender : Appender + /// The previous link. + /// The cache key. + /// previousLink;previousLink is null. + /// cacheKey is null or empty.;cacheKey + public InvalidateCacheAppender(ILink previousLink, string cacheKey) : base(previousLink) { - readonly string m_CacheKey; - - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// The cache key. - /// previousLink;previousLink is null. - /// cacheKey is null or empty.;cacheKey - public InvalidateCacheAppender(ILink previousLink, string cacheKey) : base(previousLink) - { - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - m_CacheKey = cacheKey; - } + m_CacheKey = cacheKey; + } - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - public override TResult Execute(object? state = null) - { - DataSource.Cache.Invalidate(m_CacheKey); + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + public override TResult Execute(object? state = null) + { + DataSource.Cache.Invalidate(m_CacheKey); - return PreviousLink.Execute(state); - } + return PreviousLink.Execute(state); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - await DataSource.Cache.InvalidateAsync(m_CacheKey).ConfigureAwait(false); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + await DataSource.Cache.InvalidateAsync(m_CacheKey).ConfigureAwait(false); - return await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); - } + return await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/KeyJoinAppender`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/KeyJoinAppender`2.cs index 21044ff5c..c5a6a6a84 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/KeyJoinAppender`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/KeyJoinAppender`2.cs @@ -1,133 +1,110 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +internal sealed class KeyJoinAppender : Appender, List>, List> + where TKey : notnull { - internal sealed class KeyJoinAppender : Appender, List>, List> - where TKey : notnull - { - readonly Func m_ForeignKeyExpression; - readonly JoinOptions m_JoinOptions; - readonly Func m_PrimaryKeyExpression; - readonly Func> m_TargetCollectionExpression; + readonly Func m_ForeignKeyExpression; + readonly JoinOptions m_JoinOptions; + readonly Func m_PrimaryKeyExpression; + readonly Func> m_TargetCollectionExpression; - public KeyJoinAppender(ILink, List>> previousLink, Func primaryKeyExpression, Func foreignKeyExpression, Func> targetCollectionExpression, JoinOptions joinOptions) : base(previousLink) - { - m_ForeignKeyExpression = foreignKeyExpression ?? throw new ArgumentNullException(nameof(foreignKeyExpression), $"{nameof(foreignKeyExpression)} is null."); - m_PrimaryKeyExpression = primaryKeyExpression ?? throw new ArgumentNullException(nameof(primaryKeyExpression), $"{nameof(primaryKeyExpression)} is null."); - m_TargetCollectionExpression = targetCollectionExpression ?? throw new ArgumentNullException(nameof(targetCollectionExpression), $"{nameof(targetCollectionExpression)} is null."); - m_JoinOptions = joinOptions; - } + public KeyJoinAppender(ILink, List>> previousLink, Func primaryKeyExpression, Func foreignKeyExpression, Func> targetCollectionExpression, JoinOptions joinOptions) : base(previousLink) + { + m_ForeignKeyExpression = foreignKeyExpression ?? throw new ArgumentNullException(nameof(foreignKeyExpression), $"{nameof(foreignKeyExpression)} is null."); + m_PrimaryKeyExpression = primaryKeyExpression ?? throw new ArgumentNullException(nameof(primaryKeyExpression), $"{nameof(primaryKeyExpression)} is null."); + m_TargetCollectionExpression = targetCollectionExpression ?? throw new ArgumentNullException(nameof(targetCollectionExpression), $"{nameof(targetCollectionExpression)} is null."); + m_JoinOptions = joinOptions; + } - public KeyJoinAppender(ILink, List>> previousLink, Func primaryKeyExpression, Func foreignKeyExpression, string targetCollectionName, JoinOptions joinOptions) : base(previousLink) - { - if (string.IsNullOrEmpty(targetCollectionName)) - throw new ArgumentException($"{nameof(targetCollectionName)} is null or empty.", nameof(targetCollectionName)); + public KeyJoinAppender(ILink, List>> previousLink, Func primaryKeyExpression, Func foreignKeyExpression, string targetCollectionName, JoinOptions joinOptions) : base(previousLink) + { + if (string.IsNullOrEmpty(targetCollectionName)) + throw new ArgumentException($"{nameof(targetCollectionName)} is null or empty.", nameof(targetCollectionName)); - var targetPropertyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[targetCollectionName]; //don't inline this variable. - m_TargetCollectionExpression = (p) => (ICollection)(targetPropertyStub.InvokeGet(p!) ?? $"{targetCollectionName} is null. Expected a non-null collection."); + var targetPropertyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[targetCollectionName]; //don't inline this variable. + m_TargetCollectionExpression = (p) => (ICollection)(targetPropertyStub.InvokeGet(p!) ?? $"{targetCollectionName} is null. Expected a non-null collection."); - m_ForeignKeyExpression = foreignKeyExpression ?? throw new ArgumentNullException(nameof(foreignKeyExpression), $"{nameof(foreignKeyExpression)} is null."); - m_PrimaryKeyExpression = primaryKeyExpression ?? throw new ArgumentNullException(nameof(primaryKeyExpression), $"{nameof(primaryKeyExpression)} is null."); - m_JoinOptions = joinOptions; - } + m_ForeignKeyExpression = foreignKeyExpression ?? throw new ArgumentNullException(nameof(foreignKeyExpression), $"{nameof(foreignKeyExpression)} is null."); + m_PrimaryKeyExpression = primaryKeyExpression ?? throw new ArgumentNullException(nameof(primaryKeyExpression), $"{nameof(primaryKeyExpression)} is null."); + m_JoinOptions = joinOptions; + } - public KeyJoinAppender(ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions) : base(previousLink) - { - if (string.IsNullOrEmpty(primaryKeyName)) - throw new ArgumentException($"{nameof(primaryKeyName)} is null or empty.", nameof(primaryKeyName)); + public KeyJoinAppender(ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions) : base(previousLink) + { + if (string.IsNullOrEmpty(primaryKeyName)) + throw new ArgumentException($"{nameof(primaryKeyName)} is null or empty.", nameof(primaryKeyName)); - if (string.IsNullOrEmpty(foreignKeyName)) - throw new ArgumentException($"{nameof(foreignKeyName)} is null or empty.", nameof(foreignKeyName)); + if (string.IsNullOrEmpty(foreignKeyName)) + throw new ArgumentException($"{nameof(foreignKeyName)} is null or empty.", nameof(foreignKeyName)); - if (string.IsNullOrEmpty(targetCollectionName)) - throw new ArgumentException($"{nameof(targetCollectionName)} is null or empty.", nameof(targetCollectionName)); + if (string.IsNullOrEmpty(targetCollectionName)) + throw new ArgumentException($"{nameof(targetCollectionName)} is null or empty.", nameof(targetCollectionName)); - var primaryKeyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[primaryKeyName]; //don't inline this variable. - m_PrimaryKeyExpression = (p) => (TKey)primaryKeyStub.InvokeGet(p!)!; + var primaryKeyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[primaryKeyName]; //don't inline this variable. + m_PrimaryKeyExpression = (p) => (TKey)primaryKeyStub.InvokeGet(p!)!; - var foreignKeyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[foreignKeyName]; //don't inline this variable. - m_ForeignKeyExpression = (p) => (TKey)foreignKeyStub.InvokeGet(p!)!; + var foreignKeyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[foreignKeyName]; //don't inline this variable. + m_ForeignKeyExpression = (p) => (TKey)foreignKeyStub.InvokeGet(p!)!; - var targetPropertyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[targetCollectionName]; //don't inline this variable. - m_TargetCollectionExpression = (p) => (ICollection)(targetPropertyStub.InvokeGet(p!) ?? $"{targetCollectionName} is null. Expected a non-null collection."); + var targetPropertyStub = MetadataCache.GetMetadata(typeof(T1)).Properties[targetCollectionName]; //don't inline this variable. + m_TargetCollectionExpression = (p) => (ICollection)(targetPropertyStub.InvokeGet(p!) ?? $"{targetCollectionName} is null. Expected a non-null collection."); - m_JoinOptions = joinOptions; - } + m_JoinOptions = joinOptions; + } - public override List Execute(object? state = null) - { - var result = PreviousLink.Execute(state); - Match(result); - return result.Item1; - } + public override List Execute(object? state = null) + { + var result = PreviousLink.Execute(state); + Match(result); + return result.Item1; + } - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); - Match(result); - return result.Item1; - } + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); + Match(result); + return result.Item1; + } - void Match(Tuple, List> result) - { - var ignoreUnmatchedChildren = m_JoinOptions.HasFlag(JoinOptions.IgnoreUnmatchedChildren); - var multipleParents = m_JoinOptions.HasFlag(JoinOptions.MultipleParents); + void Match(Tuple, List> result) + { + var ignoreUnmatchedChildren = m_JoinOptions.HasFlag(JoinOptions.IgnoreUnmatchedChildren); + var multipleParents = m_JoinOptions.HasFlag(JoinOptions.MultipleParents); - var parallel = m_JoinOptions.HasFlag(JoinOptions.Parallel); + var parallel = m_JoinOptions.HasFlag(JoinOptions.Parallel); - if (multipleParents) - { - if (parallel) - MultiMatchParallel(result, ignoreUnmatchedChildren); - else - MultiMatchSerial(result, ignoreUnmatchedChildren); - } + if (multipleParents) + { + if (parallel) + MultiMatchParallel(result, ignoreUnmatchedChildren); else - { - if (parallel) - MatchParallel(result, ignoreUnmatchedChildren); - else - MatchSerial(result, ignoreUnmatchedChildren); - } + MultiMatchSerial(result, ignoreUnmatchedChildren); } - - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] - void MatchParallel(Tuple, List> result, bool ignoreUnmatchedChildren) + else { - //build the dictionary - var parents = result.Item1.AsParallel().ToDictionary(m_PrimaryKeyExpression, m_TargetCollectionExpression); - - Parallel.ForEach(result.Item2, child => - { - var fk = m_ForeignKeyExpression(child); - if (parents.TryGetValue(fk, out var targetCollection)) - { - lock (targetCollection) - targetCollection.Add(child); - } - else if (!ignoreUnmatchedChildren) - { - var ex = new UnexpectedDataException($"Found child object with the foreign key \"{ fk }\" that couldn't be matched to a parent. See Exception.Data[\"ChildObject\"] for details."); - ex.Data["ForeignKey"] = fk; - ex.Data["ChildObject"] = child; - throw ex; - } - }); + if (parallel) + MatchParallel(result, ignoreUnmatchedChildren); + else + MatchSerial(result, ignoreUnmatchedChildren); } + } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] - void MatchSerial(Tuple, List> result, bool ignoreUnmatchedChildren) - { - //build the dictionary - var parents = result.Item1.ToDictionary(m_PrimaryKeyExpression, m_TargetCollectionExpression); + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] + void MatchParallel(Tuple, List> result, bool ignoreUnmatchedChildren) + { + //build the dictionary + var parents = result.Item1.AsParallel().ToDictionary(m_PrimaryKeyExpression, m_TargetCollectionExpression); - foreach (var child in result.Item2) + Parallel.ForEach(result.Item2, child => { var fk = m_ForeignKeyExpression(child); if (parents.TryGetValue(fk, out var targetCollection)) { - targetCollection.Add(child); + lock (targetCollection) + targetCollection.Add(child); } else if (!ignoreUnmatchedChildren) { @@ -136,53 +113,40 @@ void MatchSerial(Tuple, List> result, bool ignoreUnmatchedChildren) ex.Data["ChildObject"] = child; throw ex; } - } - } + }); + } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] - void MultiMatchParallel(Tuple, List> result, bool ignoreUnmatchedChildren) - { - //build the dictionary - var parents1 = from p in result.Item1.AsParallel() group m_TargetCollectionExpression(p) by m_PrimaryKeyExpression(p) into g select g; - var parents2 = parents1.ToDictionary(p => p.Key); + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] + void MatchSerial(Tuple, List> result, bool ignoreUnmatchedChildren) + { + //build the dictionary + var parents = result.Item1.ToDictionary(m_PrimaryKeyExpression, m_TargetCollectionExpression); - Parallel.ForEach(result.Item2, child => - { - var fk = m_ForeignKeyExpression(child); - if (fk == null) - { - if (!ignoreUnmatchedChildren) - { - var ex = new UnexpectedDataException($"Found child object with a null foreign key. See Exception.Data[\"ChildObject\"] for details."); - ex.Data["ForeignKey"] = fk; - ex.Data["ChildObject"] = child; - throw ex; - } - } - else if (parents2.TryGetValue(fk, out var targetCollections)) - { - foreach (var targetCollection in targetCollections) - lock (targetCollection) - targetCollection.Add(child); - } - else if (!ignoreUnmatchedChildren) - { - var ex = new UnexpectedDataException($"Found child object with the foreign key \"{ fk }\" that couldn't be matched to a parent. See Exception.Data[\"ChildObject\"] for details."); - ex.Data["ForeignKey"] = fk; - ex.Data["ChildObject"] = child; - throw ex; - } - }); + foreach (var child in result.Item2) + { + var fk = m_ForeignKeyExpression(child); + if (parents.TryGetValue(fk, out var targetCollection)) + { + targetCollection.Add(child); + } + else if (!ignoreUnmatchedChildren) + { + var ex = new UnexpectedDataException($"Found child object with the foreign key \"{ fk }\" that couldn't be matched to a parent. See Exception.Data[\"ChildObject\"] for details."); + ex.Data["ForeignKey"] = fk; + ex.Data["ChildObject"] = child; + throw ex; + } } + } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] - void MultiMatchSerial(Tuple, List> result, bool ignoreUnmatchedChildren) - { - //build the dictionary - var parents1 = from p in result.Item1 group m_TargetCollectionExpression(p) by m_PrimaryKeyExpression(p) into g select g; - var parents2 = parents1.ToDictionary(p => p.Key); + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] + void MultiMatchParallel(Tuple, List> result, bool ignoreUnmatchedChildren) + { + //build the dictionary + var parents1 = from p in result.Item1.AsParallel() group m_TargetCollectionExpression(p) by m_PrimaryKeyExpression(p) into g select g; + var parents2 = parents1.ToDictionary(p => p.Key); - foreach (var child in result.Item2) + Parallel.ForEach(result.Item2, child => { var fk = m_ForeignKeyExpression(child); if (fk == null) @@ -198,7 +162,8 @@ void MultiMatchSerial(Tuple, List> result, bool ignoreUnmatchedChil else if (parents2.TryGetValue(fk, out var targetCollections)) { foreach (var targetCollection in targetCollections) - targetCollection.Add(child); + lock (targetCollection) + targetCollection.Add(child); } else if (!ignoreUnmatchedChildren) { @@ -207,6 +172,40 @@ void MultiMatchSerial(Tuple, List> result, bool ignoreUnmatchedChil ex.Data["ChildObject"] = child; throw ex; } + }); + } + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ChildObject")] + void MultiMatchSerial(Tuple, List> result, bool ignoreUnmatchedChildren) + { + //build the dictionary + var parents1 = from p in result.Item1 group m_TargetCollectionExpression(p) by m_PrimaryKeyExpression(p) into g select g; + var parents2 = parents1.ToDictionary(p => p.Key); + + foreach (var child in result.Item2) + { + var fk = m_ForeignKeyExpression(child); + if (fk == null) + { + if (!ignoreUnmatchedChildren) + { + var ex = new UnexpectedDataException($"Found child object with a null foreign key. See Exception.Data[\"ChildObject\"] for details."); + ex.Data["ForeignKey"] = fk; + ex.Data["ChildObject"] = child; + throw ex; + } + } + else if (parents2.TryGetValue(fk, out var targetCollections)) + { + foreach (var targetCollection in targetCollections) + targetCollection.Add(child); + } + else if (!ignoreUnmatchedChildren) + { + var ex = new UnexpectedDataException($"Found child object with the foreign key \"{ fk }\" that couldn't be matched to a parent. See Exception.Data[\"ChildObject\"] for details."); + ex.Data["ForeignKey"] = fk; + ex.Data["ChildObject"] = child; + throw ex; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/NonNullLink`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/NonNullLink`1.cs index d3665e8f4..d84a08a7b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/NonNullLink`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/NonNullLink`1.cs @@ -1,46 +1,45 @@ -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Converts an null returning ILink into a non-null returning ILink. +/// +/// +/// If the previous link returns a null, this will throw an exception. +internal class NonNullLink : Appender where T : class { /// - /// Converts an null returning ILink into a non-null returning ILink. + ///Initializes a new instance of the class. /// - /// - /// If the previous link returns a null, this will throw an exception. - internal class NonNullLink : Appender where T : class + /// The previous link. + public NonNullLink(ILink previousLink) : base(previousLink) { - /// - ///Initializes a new instance of the class. - /// - /// The previous link. - public NonNullLink(ILink previousLink) : base(previousLink) - { - } + } - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// If you don't override this method, it will call execute on the previous link. - public override T Execute(object? state = null) - { - var result = PreviousLink.Execute(state); - if (result == null) - throw new MissingDataException("An unexpected null was returned."); - return result; - } + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// If you don't override this method, it will call execute on the previous link. + public override T Execute(object? state = null) + { + var result = PreviousLink.Execute(state); + if (result == null) + throw new MissingDataException("An unexpected null was returned."); + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// If you don't override this method, it will call execute on the previous link. - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); - if (result == null) - throw new MissingDataException("An unexpected null was returned."); - return result; - } + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// If you don't override this method, it will call execute on the previous link. + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); + if (result == null) + throw new MissingDataException("An unexpected null was returned."); + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ReadOrCacheResultAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ReadOrCacheResultAppender`1.cs index 713069d7b..4be414766 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ReadOrCacheResultAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ReadOrCacheResultAppender`1.cs @@ -1,69 +1,68 @@ -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Reads the cache. If the value isn't found, the execute the previous link and cache the result. +/// +/// The type of the t result type. +/// If this successfully reads from the cache, it will prevent prior links from executing. +internal sealed class ReadOrCacheResultAppender : Appender, ICacheLink { + readonly string m_CacheKey; + readonly CachePolicy? m_Policy; + /// - /// Reads the cache. If the value isn't found, the execute the previous link and cache the result. + /// Initializes a new instance of the class. /// - /// The type of the t result type. - /// If this successfully reads from the cache, it will prevent prior links from executing. - internal sealed class ReadOrCacheResultAppender : Appender, ICacheLink + /// The previous link. + /// The cache key. + /// Optional cache policy. + /// cacheKey + public ReadOrCacheResultAppender(ILink previousLink, string cacheKey, CachePolicy? policy) : base(previousLink) { - readonly string m_CacheKey; - readonly CachePolicy? m_Policy; + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// The cache key. - /// Optional cache policy. - /// cacheKey - public ReadOrCacheResultAppender(ILink previousLink, string cacheKey, CachePolicy? policy) : base(previousLink) - { - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - - m_Policy = policy; - m_CacheKey = cacheKey; - } + m_Policy = policy; + m_CacheKey = cacheKey; + } - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - public override TResult Execute(object? state = null) - { - if (DataSource.Cache.TryRead(m_CacheKey, out TResult result)) - return result; + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + public override TResult Execute(object? state = null) + { + if (DataSource.Cache.TryRead(m_CacheKey, out TResult result)) + return result; - result = PreviousLink.Execute(state); + result = PreviousLink.Execute(state); - DataSource.Cache.Write(m_CacheKey, result, m_Policy); + DataSource.Cache.Write(m_CacheKey, result, m_Policy); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var temp = await DataSource.Cache.TryReadAsync(m_CacheKey).ConfigureAwait(false); - if (temp.KeyFound) - return temp.Value; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var temp = await DataSource.Cache.TryReadAsync(m_CacheKey).ConfigureAwait(false); + if (temp.KeyFound) + return temp.Value; - TResult result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); + TResult result = await PreviousLink.ExecuteAsync(state).ConfigureAwait(false); - DataSource.Cache.Write(m_CacheKey, result, m_Policy); + DataSource.Cache.Write(m_CacheKey, result, m_Policy); - return result; - } + return result; + } - void ICacheLink.Invalidate() - { - DataSource.Cache.Invalidate(m_CacheKey); - } + void ICacheLink.Invalidate() + { + DataSource.Cache.Invalidate(m_CacheKey); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/SequentialAccessModeAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/SequentialAccessModeAppender`1.cs index c9b331957..f31f2e5a3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/SequentialAccessModeAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/SequentialAccessModeAppender`1.cs @@ -1,33 +1,32 @@ using Tortuga.Chain.Core; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Class SequentialAccessModeAppender. +/// Implements the +/// +/// The type of the t result. +/// +internal sealed class SequentialAccessModeAppender : Appender { + readonly bool m_SequentialAccessMode; + /// - /// Class SequentialAccessModeAppender. - /// Implements the + /// Initializes a new instance of the class. /// - /// The type of the t result. - /// - internal sealed class SequentialAccessModeAppender : Appender + /// The previous link. + /// if set to true enable sequential access. + public SequentialAccessModeAppender(ILink previousLink, bool sequentialAccessMode) + : base(previousLink) { - readonly bool m_SequentialAccessMode; - - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// if set to true enable sequential access. - public SequentialAccessModeAppender(ILink previousLink, bool sequentialAccessMode) - : base(previousLink) - { - m_SequentialAccessMode = sequentialAccessMode; - } + m_SequentialAccessMode = sequentialAccessMode; + } - protected override void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); - e.CommandBuilder.SequentialAccessMode = m_SequentialAccessMode; - } + protected override void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + e.CommandBuilder.SequentialAccessMode = m_SequentialAccessMode; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/StrictModeAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/StrictModeAppender`1.cs index c22a73b3b..20870aa36 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/StrictModeAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/StrictModeAppender`1.cs @@ -1,33 +1,32 @@ using Tortuga.Chain.Core; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Class StrictModeAppender. +/// Implements the +/// +/// The type of the t result. +/// +internal sealed class StrictModeAppender : Appender { + readonly bool m_StrictMode; + /// - /// Class StrictModeAppender. - /// Implements the + /// Initializes a new instance of the class. /// - /// The type of the t result. - /// - internal sealed class StrictModeAppender : Appender + /// The previous link. + /// if set to true [strict mode]. + public StrictModeAppender(ILink previousLink, bool strictMode) + : base(previousLink) { - readonly bool m_StrictMode; - - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// if set to true [strict mode]. - public StrictModeAppender(ILink previousLink, bool strictMode) - : base(previousLink) - { - m_StrictMode = strictMode; - } + m_StrictMode = strictMode; + } - protected override void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); - e.CommandBuilder.StrictMode = m_StrictMode; - } + protected override void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + e.CommandBuilder.StrictMode = m_StrictMode; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TimeoutAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TimeoutAppender`1.cs index 1fadb284e..eedc54067 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TimeoutAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TimeoutAppender`1.cs @@ -1,36 +1,35 @@ using Tortuga.Chain.Core; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Class TimeoutAppender. +/// +/// The type of the t result. +internal sealed class TimeoutAppender : Appender { + readonly TimeSpan m_Timeout; + /// - /// Class TimeoutAppender. + /// Initializes a new instance of the class. /// - /// The type of the t result. - internal sealed class TimeoutAppender : Appender + /// The previous link. + /// The timeout. + public TimeoutAppender(ILink previousLink, TimeSpan timeout) + : base(previousLink) { - readonly TimeSpan m_Timeout; - - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// The timeout. - public TimeoutAppender(ILink previousLink, TimeSpan timeout) - : base(previousLink) - { - m_Timeout = timeout; - } + m_Timeout = timeout; + } - /// - /// Override this if you want to examine or modify the DBCommand before it is executed. - /// - /// The instance containing the event data. - /// nam - f(e), "e is - protected override void OnCommandBuilt(CommandBuiltEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); - e.Command.CommandTimeout = (int)m_Timeout.TotalSeconds; - } + /// + /// Override this if you want to examine or modify the DBCommand before it is executed. + /// + /// The instance containing the event data. + /// nam - f(e), "e is + protected override void OnCommandBuilt(CommandBuiltEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + e.Command.CommandTimeout = (int)m_Timeout.TotalSeconds; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TraceAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TraceAppender`1.cs index 75a69a473..f2b43a316 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TraceAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TraceAppender`1.cs @@ -2,61 +2,60 @@ using System.IO; using Tortuga.Chain.Core; -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Class TraceAppender. +/// +/// The type of the t result. +internal sealed class TraceAppender : Appender { + readonly TextWriter? m_Stream; + /// - /// Class TraceAppender. + /// Initializes a new instance of the class. /// - /// The type of the t result. - internal sealed class TraceAppender : Appender + /// The previous link. + public TraceAppender(ILink previousLink) + : base(previousLink) { - readonly TextWriter? m_Stream; - - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - public TraceAppender(ILink previousLink) - : base(previousLink) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// The optional stream to direct the output. If null, Debug is used.. - public TraceAppender(ILink previousLink, TextWriter stream) : this(previousLink) - { - m_Stream = stream; - } + /// + /// Initializes a new instance of the class. + /// + /// The previous link. + /// The optional stream to direct the output. If null, Debug is used.. + public TraceAppender(ILink previousLink, TextWriter stream) : this(previousLink) + { + m_Stream = stream; + } - /// - /// Override this if you want to examine or modify the DBCommand before it is executed. - /// - /// The instance containing the event data. - protected override void OnCommandBuilt(CommandBuiltEventArgs e) + /// + /// Override this if you want to examine or modify the DBCommand before it is executed. + /// + /// The instance containing the event data. + protected override void OnCommandBuilt(CommandBuiltEventArgs e) + { + if (m_Stream == null) { - if (m_Stream == null) + Debug.WriteLine("Command Text: " + e.Command.CommandText); + Debug.Indent(); + foreach (var parameter in e.Command.Parameters.Enumerate()) { - Debug.WriteLine("Command Text: " + e.Command.CommandText); - Debug.Indent(); - foreach (var parameter in e.Command.Parameters.Enumerate()) - { - var valueText = (parameter.Value == null || parameter.Value == DBNull.Value) ? "" : parameter.Value.ToString(); - Debug.WriteLine($"Parameter: {parameter.ParameterName} = {valueText}"); - } - Debug.Unindent(); + var valueText = (parameter.Value == null || parameter.Value == DBNull.Value) ? "" : parameter.Value.ToString(); + Debug.WriteLine($"Parameter: {parameter.ParameterName} = {valueText}"); } - else - { - m_Stream.WriteLine("Command Text: " + e.Command.CommandText); + Debug.Unindent(); + } + else + { + m_Stream.WriteLine("Command Text: " + e.Command.CommandText); - foreach (var parameter in e.Command.Parameters.Enumerate()) - { - var valueText = (parameter.Value == null || parameter.Value == DBNull.Value) ? "" : parameter.Value.ToString(); - m_Stream.WriteLine($" Parameter: {parameter.ParameterName} = {valueText}"); - } + foreach (var parameter in e.Command.Parameters.Enumerate()) + { + var valueText = (parameter.Value == null || parameter.Value == DBNull.Value) ? "" : parameter.Value.ToString(); + m_Stream.WriteLine($" Parameter: {parameter.ParameterName} = {valueText}"); } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TransformLink`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TransformLink`2.cs index cc08c57c2..8484fd4dd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TransformLink`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/TransformLink`2.cs @@ -1,27 +1,26 @@ -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Performs a transformation on a result. +/// +internal class TransformLink : Appender { - /// - /// Performs a transformation on a result. - /// - internal class TransformLink : Appender - { - Func m_Transformation; + Func m_Transformation; - public TransformLink(ILink previousLink, Func transformation) : base(previousLink) - { - m_Transformation = transformation; - } + public TransformLink(ILink previousLink, Func transformation) : base(previousLink) + { + m_Transformation = transformation; + } - public override TResult Execute(object? state = null) - { - var result = PreviousLink.Execute(state); - return m_Transformation(result); - } + public override TResult Execute(object? state = null) + { + var result = PreviousLink.Execute(state); + return m_Transformation(result); + } - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); - return m_Transformation(result); - } + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); + return m_Transformation(result); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ValueNonNullLink`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ValueNonNullLink`1.cs index dc6ddc9fa..adc4873aa 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ValueNonNullLink`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Appenders/ValueNonNullLink`1.cs @@ -1,46 +1,45 @@ -namespace Tortuga.Chain.Appenders +namespace Tortuga.Chain.Appenders; + +/// +/// Converts an null returning ILink into a non-null returning ILink. +/// +/// +/// If the previous link returns a null, this will throw an exception. +internal class ValueNonNullLink : Appender where T : struct { /// - /// Converts an null returning ILink into a non-null returning ILink. + ///Initializes a new instance of the class. /// - /// - /// If the previous link returns a null, this will throw an exception. - internal class ValueNonNullLink : Appender where T : struct + /// The previous link. + public ValueNonNullLink(ILink previousLink) : base(previousLink) { - /// - ///Initializes a new instance of the class. - /// - /// The previous link. - public ValueNonNullLink(ILink previousLink) : base(previousLink) - { - } + } - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// If you don't override this method, it will call execute on the previous link. - public override T Execute(object? state = null) - { - var result = PreviousLink.Execute(state); - if (result == null) - throw new MissingDataException("An unexpected null was returned."); - return result.Value; - } + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// If you don't override this method, it will call execute on the previous link. + public override T Execute(object? state = null) + { + var result = PreviousLink.Execute(state); + if (result == null) + throw new MissingDataException("An unexpected null was returned."); + return result.Value; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// If you don't override this method, it will call execute on the previous link. - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); - if (result == null) - throw new MissingDataException("An unexpected null was returned."); - return result.Value; - } + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// If you don't override this method, it will call execute on the previous link. + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = await PreviousLink.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); + if (result == null) + throw new MissingDataException("An unexpected null was returned."); + return result.Value; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRule.cs index 3c46f7a3d..dc9422916 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRule.cs @@ -1,25 +1,24 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// Base class for all audit rules. +/// +abstract public class AuditRule { /// - /// Base class for all audit rules. + /// Initializes a new instance of the class. /// - abstract public class AuditRule + /// The rule applies when. + protected AuditRule(OperationTypes appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - protected AuditRule(OperationTypes appliesWhen) - { - AppliesWhen = appliesWhen; - } - - /// - /// Indicates when the rule is applicable. - /// - /// - /// The rule applies when. - /// - public OperationTypes AppliesWhen { get; } + AppliesWhen = appliesWhen; } + + /// + /// Indicates when the rule is applicable. + /// + /// + /// The rule applies when. + /// + public OperationTypes AppliesWhen { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRuleCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRuleCollection.cs index c91c3b3e4..905447ab4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRuleCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/AuditRuleCollection.cs @@ -3,129 +3,128 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// An immutable collection of rules. +/// +/// +public class AuditRuleCollection : IReadOnlyList { /// - /// An immutable collection of rules. + /// Returns an empty RulesCollection. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly AuditRuleCollection Empty = new AuditRuleCollection(); + + readonly ImmutableArray m_List; + readonly ImmutableArray m_Validation; + + /// + /// Initializes a new instance of the class. + /// + /// The list of rules used to build this collection. + public AuditRuleCollection(IEnumerable rules) + { + m_List = ImmutableArray.CreateRange(rules); + m_Validation = ImmutableArray.CreateRange(m_List.OfType()); + + SoftDeleteForSelect = this.Where(r => r.AppliesWhen.HasFlag(OperationTypes.Select)).OfType().ToImmutableArray(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The list of rules to be added upon. + /// The additional rules. + /// + /// baseRules + /// or + /// additionalRules + /// + public AuditRuleCollection(AuditRuleCollection baseRules, IEnumerable additionalRules) + { + if (baseRules == null) + throw new ArgumentNullException(nameof(baseRules), $"{nameof(baseRules)} is null."); + if (additionalRules == null) + throw new ArgumentNullException(nameof(additionalRules), $"{nameof(additionalRules)} is null."); + + m_List = baseRules.m_List.AddRange(additionalRules); + m_Validation = ImmutableArray.CreateRange(m_List.OfType()); + + SoftDeleteForSelect = this.Where(r => r.AppliesWhen.HasFlag(OperationTypes.Select)).OfType().ToImmutableArray(); + } + + /// + /// Initializes a new instance of the class. + /// + AuditRuleCollection() + { + m_List = ImmutableArray.Create(); + m_Validation = ImmutableArray.Create(); + + SoftDeleteForSelect = ImmutableArray.Create(); + } + + /// + /// Gets the number of elements in the collection. + /// + public int Count => m_List.Length; + + /// + /// Gets the soft delete rules for select. + /// + /// + /// The soft delete for select. + /// + internal ImmutableArray SoftDeleteForSelect { get; } + + /// + /// Gets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// + public AuditRule this[int index] => m_List[index]; + + /// + /// Returns an enumerator that iterates through the collection. /// - /// - public class AuditRuleCollection : IReadOnlyList + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() => ((IEnumerable)m_List).GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)m_List).GetEnumerator(); + + /// + /// Indicates whether or not a soft delete should be performed. + /// + /// The table. + /// + public bool UseSoftDelete(TableOrViewMetadata table) + { + return m_List.Where(r => r.AppliesWhen.HasFlag(OperationTypes.Delete)).OfType().Any(r => table.Columns.Any(c => c.SqlName.Equals(r.ColumnName, StringComparison.OrdinalIgnoreCase))); + } + + internal void CheckValidation(object argumentValue) + { + for (int i = 0; i < m_Validation.Length; i++) + m_Validation[i].CheckValue(argumentValue); + } + + internal IEnumerable GetRestrictionsForColumn(string objectName, string? sqlName, string? clrName) + { + return m_List.OfType().Where(c => + (c.ObjectName == null || c.ObjectName.Equals(objectName, StringComparison.OrdinalIgnoreCase)) + && + (c.ColumnName.Equals(sqlName, StringComparison.OrdinalIgnoreCase) || c.ColumnName.Equals(clrName, StringComparison.OrdinalIgnoreCase))); + } + + internal IEnumerable GetRulesForColumn(string? sqlName, string? clrName, OperationTypes filterByOperationType) { - /// - /// Returns an empty RulesCollection. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly AuditRuleCollection Empty = new AuditRuleCollection(); - - readonly ImmutableArray m_List; - readonly ImmutableArray m_Validation; - - /// - /// Initializes a new instance of the class. - /// - /// The list of rules used to build this collection. - public AuditRuleCollection(IEnumerable rules) - { - m_List = ImmutableArray.CreateRange(rules); - m_Validation = ImmutableArray.CreateRange(m_List.OfType()); - - SoftDeleteForSelect = this.Where(r => r.AppliesWhen.HasFlag(OperationTypes.Select)).OfType().ToImmutableArray(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The list of rules to be added upon. - /// The additional rules. - /// - /// baseRules - /// or - /// additionalRules - /// - public AuditRuleCollection(AuditRuleCollection baseRules, IEnumerable additionalRules) - { - if (baseRules == null) - throw new ArgumentNullException(nameof(baseRules), $"{nameof(baseRules)} is null."); - if (additionalRules == null) - throw new ArgumentNullException(nameof(additionalRules), $"{nameof(additionalRules)} is null."); - - m_List = baseRules.m_List.AddRange(additionalRules); - m_Validation = ImmutableArray.CreateRange(m_List.OfType()); - - SoftDeleteForSelect = this.Where(r => r.AppliesWhen.HasFlag(OperationTypes.Select)).OfType().ToImmutableArray(); - } - - /// - /// Initializes a new instance of the class. - /// - AuditRuleCollection() - { - m_List = ImmutableArray.Create(); - m_Validation = ImmutableArray.Create(); - - SoftDeleteForSelect = ImmutableArray.Create(); - } - - /// - /// Gets the number of elements in the collection. - /// - public int Count => m_List.Length; - - /// - /// Gets the soft delete rules for select. - /// - /// - /// The soft delete for select. - /// - internal ImmutableArray SoftDeleteForSelect { get; } - - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// - public AuditRule this[int index] => m_List[index]; - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() => ((IEnumerable)m_List).GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)m_List).GetEnumerator(); - - /// - /// Indicates whether or not a soft delete should be performed. - /// - /// The table. - /// - public bool UseSoftDelete(TableOrViewMetadata table) - { - return m_List.Where(r => r.AppliesWhen.HasFlag(OperationTypes.Delete)).OfType().Any(r => table.Columns.Any(c => c.SqlName.Equals(r.ColumnName, StringComparison.OrdinalIgnoreCase))); - } - - internal void CheckValidation(object argumentValue) - { - for (int i = 0; i < m_Validation.Length; i++) - m_Validation[i].CheckValue(argumentValue); - } - - internal IEnumerable GetRestrictionsForColumn(string objectName, string? sqlName, string? clrName) - { - return m_List.OfType().Where(c => - (c.ObjectName == null || c.ObjectName.Equals(objectName, StringComparison.OrdinalIgnoreCase)) - && - (c.ColumnName.Equals(sqlName, StringComparison.OrdinalIgnoreCase) || c.ColumnName.Equals(clrName, StringComparison.OrdinalIgnoreCase))); - } - - internal IEnumerable GetRulesForColumn(string? sqlName, string? clrName, OperationTypes filterByOperationType) - { - return m_List.OfType().Where(c => (c.AppliesWhen & filterByOperationType) > 0 && (c.ColumnName.Equals(sqlName, StringComparison.OrdinalIgnoreCase) || c.ColumnName.Equals(clrName, StringComparison.OrdinalIgnoreCase))); - } + return m_List.OfType().Where(c => (c.AppliesWhen & filterByOperationType) > 0 && (c.ColumnName.Equals(sqlName, StringComparison.OrdinalIgnoreCase) || c.ColumnName.Equals(clrName, StringComparison.OrdinalIgnoreCase))); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnRule.cs index 7afb5cafd..e3c63c5b8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnRule.cs @@ -1,40 +1,39 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// This is the base class for rules that affect a single column. +/// +/// +abstract public class ColumnRule : AuditRule { /// - /// This is the base class for rules that affect a single column. + /// Initializes a new instance of the class. /// - /// - abstract public class ColumnRule : AuditRule + /// Name of the column. + /// The applies when. + /// + protected ColumnRule(string columnName, OperationTypes appliesWhen) : base(appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// The applies when. - /// - protected ColumnRule(string columnName, OperationTypes appliesWhen) : base(appliesWhen) - { - if (string.IsNullOrEmpty(columnName)) - throw new ArgumentException($"{nameof(columnName)} is null or empty.", nameof(columnName)); + if (string.IsNullOrEmpty(columnName)) + throw new ArgumentException($"{nameof(columnName)} is null or empty.", nameof(columnName)); - ColumnName = columnName; - } + ColumnName = columnName; + } - /// - /// Gets the name of the column. - /// - /// - /// The name of the column. - /// - public string ColumnName { get; } + /// + /// Gets the name of the column. + /// + /// + /// The name of the column. + /// + public string ColumnName { get; } - /// - /// Generates the value to be used for the operation. - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - public abstract object? GenerateValue(object? argumentValue, object? userValue, object? currentValue); - } + /// + /// Generates the value to be used for the operation. + /// + /// The argument value. + /// The user value. + /// The current value. Used when the rule is conditionally applied. + /// + public abstract object? GenerateValue(object? argumentValue, object? userValue, object? currentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnValueGenerator.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnValueGenerator.cs index fdc4014e7..3dde183ca 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnValueGenerator.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ColumnValueGenerator.cs @@ -1,11 +1,10 @@ -namespace Tortuga.Chain.AuditRules -{ - /// - /// Rule Value Generator - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - public delegate object ColumnValueGenerator(object? argumentValue, object? userValue, object? currentValue); -} +namespace Tortuga.Chain.AuditRules; + +/// +/// Rule Value Generator +/// +/// The argument value. +/// The user value. +/// The current value. Used when the rule is conditionally applied. +/// +public delegate object ColumnValueGenerator(object? argumentValue, object? userValue, object? currentValue); diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeOffsetRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeOffsetRule.cs index 2bb34c1f8..a61d5b2da 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeOffsetRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeOffsetRule.cs @@ -1,33 +1,32 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// Applies the current DateTimeOffset value to the indicated column. +/// +/// +public class DateTimeOffsetRule : ColumnRule { /// - /// Applies the current DateTimeOffset value to the indicated column. + /// Initializes a new instance of the class. /// - /// - public class DateTimeOffsetRule : ColumnRule + /// Name of the column. + /// The rule can be applied to insert, update, and/or soft delete operations. + /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete + /// + /// This will have no effect on hard deletes. + /// + public DateTimeOffsetRule(string columnName, OperationTypes appliesWhen) : base(columnName, appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// The rule can be applied to insert, update, and/or soft delete operations. - /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete - /// - /// This will have no effect on hard deletes. - /// - public DateTimeOffsetRule(string columnName, OperationTypes appliesWhen) : base(columnName, appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); - } - - /// - /// Generates the value to be used for the operation. - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) => DateTimeOffset.Now; + if (appliesWhen.HasFlag(OperationTypes.Select)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); } + + /// + /// Generates the value to be used for the operation. + /// + /// The argument value. + /// The user value. + /// The current value. Used when the rule is conditionally applied. + /// + public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) => DateTimeOffset.Now; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeRule.cs index 239069726..1872bcddd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/DateTimeRule.cs @@ -1,54 +1,53 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// Applies the current DateTime value to the indicated column. +/// +/// +public class DateTimeRule : ColumnRule { /// - /// Applies the current DateTime value to the indicated column. + /// Initializes a new instance of the class. /// - /// - public class DateTimeRule : ColumnRule + /// Name of the column. + /// The kind. + /// The rule can be applied to insert, update, and/or soft delete operations. + /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete + /// + /// This will have no effect on hard deletes. + /// + public DateTimeRule(string columnName, DateTimeKind kind, OperationTypes appliesWhen) : base(columnName, appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// The kind. - /// The rule can be applied to insert, update, and/or soft delete operations. - /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete - /// - /// This will have no effect on hard deletes. - /// - public DateTimeRule(string columnName, DateTimeKind kind, OperationTypes appliesWhen) : base(columnName, appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); - if (kind == DateTimeKind.Unspecified) - throw new ArgumentOutOfRangeException(nameof(kind)); - Kind = kind; - } + if (appliesWhen.HasFlag(OperationTypes.Select)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); + if (kind == DateTimeKind.Unspecified) + throw new ArgumentOutOfRangeException(nameof(kind)); + Kind = kind; + } - /// - /// Gets the kind. - /// - /// - /// The kind. - /// - public DateTimeKind Kind { get; } + /// + /// Gets the kind. + /// + /// + /// The kind. + /// + public DateTimeKind Kind { get; } - /// - /// Generates the value to be used for the operation. - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - /// kind is set incorrectly - public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) + /// + /// Generates the value to be used for the operation. + /// + /// The argument value. + /// The user value. + /// The current value. Used when the rule is conditionally applied. + /// + /// kind is set incorrectly + public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) + { + return Kind switch { - return Kind switch - { - DateTimeKind.Local => DateTime.Now, - DateTimeKind.Utc => DateTime.UtcNow, - _ => throw new InvalidOperationException("kind is set incorrectly"), - }; - } + DateTimeKind.Local => DateTime.Now, + DateTimeKind.Utc => DateTime.UtcNow, + _ => throw new InvalidOperationException("kind is set incorrectly"), + }; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ExceptWhenPredicate.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ExceptWhenPredicate.cs index 2b88bd01a..10b26c9e5 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ExceptWhenPredicate.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ExceptWhenPredicate.cs @@ -1,9 +1,8 @@ -namespace Tortuga.Chain.AuditRules -{ - /// - /// This delegate is used for restricting access to a column - /// - /// The user value. - /// - public delegate bool ExceptWhenPredicate(object? userValue); -} +namespace Tortuga.Chain.AuditRules; + +/// +/// This delegate is used for restricting access to a column +/// +/// The user value. +/// +public delegate bool ExceptWhenPredicate(object? userValue); diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/OperationTypes.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/OperationTypes.cs index 0427a653e..946c00744 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/OperationTypes.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/OperationTypes.cs @@ -1,51 +1,50 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// Indicates the type of operation being performed. +/// +/// Keep numbers in sync with Metadata.OperationType. +[Flags] +public enum OperationTypes { /// - /// Indicates the type of operation being performed. + /// Undefined operation. + /// + None = 0, + + /// + /// Applies the rule when performing an insert operation (including the insert portion of an Upsert) + /// + Insert = 1, + + /// + /// Applies the rule when performing an update operation (including the update portion of an Upsert) + /// + Update = 2, + + /// + /// Applies the rule when performing an insert or update operation (including the update portion of an Upsert) + /// + InsertOrUpdate = Insert | Update, + + /// + /// Applies the rule when performing a delete operation. + /// + /// Usually used for soft delete support + Delete = 4, + + /// + /// Applies the rule when performing a select operation. + /// + /// Usually used for soft delete support + Select = 8, + + /// + /// Applies the rule when performing a select or delete operation. /// - /// Keep numbers in sync with Metadata.OperationType. - [Flags] - public enum OperationTypes - { - /// - /// Undefined operation. - /// - None = 0, - - /// - /// Applies the rule when performing an insert operation (including the insert portion of an Upsert) - /// - Insert = 1, - - /// - /// Applies the rule when performing an update operation (including the update portion of an Upsert) - /// - Update = 2, - - /// - /// Applies the rule when performing an insert or update operation (including the update portion of an Upsert) - /// - InsertOrUpdate = Insert | Update, - - /// - /// Applies the rule when performing a delete operation. - /// - /// Usually used for soft delete support - Delete = 4, - - /// - /// Applies the rule when performing a select operation. - /// - /// Usually used for soft delete support - Select = 8, - - /// - /// Applies the rule when performing a select or delete operation. - /// - /// Usually used for soft delete support - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "SelectOr")] - SelectOrDelete = Delete | Select - } + /// Usually used for soft delete support + [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "SelectOr")] + SelectOrDelete = Delete | Select } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/RestrictColumn.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/RestrictColumn.cs index f5a6c9368..91ac334c5 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/RestrictColumn.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/RestrictColumn.cs @@ -1,58 +1,57 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// This rule is used to prevent users from reading or updating a column +/// +public class RestrictColumn : AuditRule { /// - /// This rule is used to prevent users from reading or updating a column + /// Initializes a new instance of the class. /// - public class RestrictColumn : AuditRule + /// Name of the database object this rule applies to. + /// Name of the column. + /// While operations are being restricted. + /// This function will return true if the rule doesn't apply to this user.. + public RestrictColumn(string objectName, string columnName, OperationTypes appliesWhen, ExceptWhenPredicate exceptWhen) : base(appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the database object this rule applies to. - /// Name of the column. - /// While operations are being restricted. - /// This function will return true if the rule doesn't apply to this user.. - public RestrictColumn(string objectName, string columnName, OperationTypes appliesWhen, ExceptWhenPredicate exceptWhen) : base(appliesWhen) - { - ColumnName = columnName; - ObjectName = objectName; - ExceptWhen = exceptWhen; - } + ColumnName = columnName; + ObjectName = objectName; + ExceptWhen = exceptWhen; + } - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// While operations are being restricted. - /// This function will return true if the rule doesn't apply to this user.. - public RestrictColumn(string columnName, OperationTypes appliesWhen, ExceptWhenPredicate exceptWhen) : base(appliesWhen) - { - ColumnName = columnName; - ExceptWhen = exceptWhen; - } + /// + /// Initializes a new instance of the class. + /// + /// Name of the column. + /// While operations are being restricted. + /// This function will return true if the rule doesn't apply to this user.. + public RestrictColumn(string columnName, OperationTypes appliesWhen, ExceptWhenPredicate exceptWhen) : base(appliesWhen) + { + ColumnName = columnName; + ExceptWhen = exceptWhen; + } - /// - /// Gets the name of the column. - /// - /// - /// The name of the column. - /// - public string ColumnName { get; } + /// + /// Gets the name of the column. + /// + /// + /// The name of the column. + /// + public string ColumnName { get; } - /// - /// Gets the except when. - /// - /// - /// The except when. - /// - public ExceptWhenPredicate ExceptWhen { get; } + /// + /// Gets the except when. + /// + /// + /// The except when. + /// + public ExceptWhenPredicate ExceptWhen { get; } - /// - /// Gets the name of the object (e.g. table, view). - /// - /// - /// The name of the object. - /// - public string? ObjectName { get; } - } + /// + /// Gets the name of the object (e.g. table, view). + /// + /// + /// The name of the object. + /// + public string? ObjectName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/SoftDeleteRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/SoftDeleteRule.cs index aa5df19c1..d46b3c20c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/SoftDeleteRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/SoftDeleteRule.cs @@ -1,48 +1,47 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// If a column matching this rule is found, then soft deletes will be applied instead of hard deletes. +/// +/// +public sealed class SoftDeleteRule : ColumnRule { /// - /// If a column matching this rule is found, then soft deletes will be applied instead of hard deletes. + /// Initializes a new instance of the class. /// - /// - public sealed class SoftDeleteRule : ColumnRule + /// Name of the column. + /// The value that represents a deleted row. + /// The rule can be applied to delete and/or select operations. + /// appliesWhen;appliesWhen may only be Select or Delete + public SoftDeleteRule(string columnName, object deletedValue, OperationTypes appliesWhen = OperationTypes.SelectOrDelete) : base(columnName, appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// The value that represents a deleted row. - /// The rule can be applied to delete and/or select operations. - /// appliesWhen;appliesWhen may only be Select or Delete - public SoftDeleteRule(string columnName, object deletedValue, OperationTypes appliesWhen = OperationTypes.SelectOrDelete) : base(columnName, appliesWhen) + switch (appliesWhen) { - switch (appliesWhen) - { - case OperationTypes.Select: - case OperationTypes.Delete: - case OperationTypes.SelectOrDelete: - break; + case OperationTypes.Select: + case OperationTypes.Delete: + case OperationTypes.SelectOrDelete: + break; - default: - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be Select or Delete"); - } - DeletedValue = deletedValue; + default: + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be Select or Delete"); } + DeletedValue = deletedValue; + } - /// - /// Gets the deleted value. - /// - /// - /// The deleted value. - /// - public object DeletedValue { get; } + /// + /// Gets the deleted value. + /// + /// + /// The deleted value. + /// + public object DeletedValue { get; } - /// - /// Generates the value to be used for the operation. - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) => DeletedValue; - } -} \ No newline at end of file + /// + /// Generates the value to be used for the operation. + /// + /// The argument value. + /// The user value. + /// The current value. Used when the rule is conditionally applied. + /// + public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) => DeletedValue; +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/UserDataRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/UserDataRule.cs index 7c5ae0d14..498c0f93e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/UserDataRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/UserDataRule.cs @@ -1,56 +1,55 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// This is a rule that overrides argument values with data on the user object. +/// +/// +/// This is usually used for CreatedBy/LastModifiedBy style columns +public class UserDataRule : ColumnRule { /// - /// This is a rule that overrides argument values with data on the user object. + /// Initializes a new instance of the class. /// - /// - /// This is usually used for CreatedBy/LastModifiedBy style columns - public class UserDataRule : ColumnRule + /// Name of the column. + /// Name of the property. + /// The rule can be applied to insert, update, and/or soft delete operations. + /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete + /// This will have no effect on hard deletes. + public UserDataRule(string columnName, string propertyName, OperationTypes appliesWhen) : base(columnName, appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// Name of the property. - /// The rule can be applied to insert, update, and/or soft delete operations. - /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete - /// This will have no effect on hard deletes. - public UserDataRule(string columnName, string propertyName, OperationTypes appliesWhen) : base(columnName, appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); + if (appliesWhen.HasFlag(OperationTypes.Select)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); - PropertyName = propertyName; - } + PropertyName = propertyName; + } - /// - /// Gets the name of the property. - /// - /// - /// The name of the property. - /// - public string PropertyName { get; } + /// + /// Gets the name of the property. + /// + /// + /// The name of the property. + /// + public string PropertyName { get; } - /// - /// Generates the value to be used for the operation. - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - /// - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "userValue")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DataSource")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "WithUser")] - public override object? GenerateValue(object? argumentValue, object? userValue, object? currentValue) - { - if (userValue == null) - throw new InvalidOperationException($"{nameof(userValue)} is null. Did you forget to call DataSource.WithUser?"); + /// + /// Generates the value to be used for the operation. + /// + /// The argument value. + /// The user value. + /// The current value. Used when the rule is conditionally applied. + /// + /// + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "userValue")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DataSource")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "WithUser")] + public override object? GenerateValue(object? argumentValue, object? userValue, object? currentValue) + { + if (userValue == null) + throw new InvalidOperationException($"{nameof(userValue)} is null. Did you forget to call DataSource.WithUser?"); - return MetadataCache.GetMetadata(userValue.GetType()).Properties[PropertyName].InvokeGet(userValue); - } + return MetadataCache.GetMetadata(userValue.GetType()).Properties[PropertyName].InvokeGet(userValue); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo.cs index fcdc3abf6..e24ade742 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo.cs @@ -1,50 +1,49 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// When this rule is in effect, objects that implement IDataErrorInfo will be checked. +/// +/// +public class ValidateWithDataErrorInfo : ValidationRule { /// - /// When this rule is in effect, objects that implement IDataErrorInfo will be checked. + /// Initializes a new instance of the class. /// - /// - public class ValidateWithDataErrorInfo : ValidationRule + /// The rule applies when. + /// appliesWhen;appliesWhen may only be a combination of Insert or Update + public ValidateWithDataErrorInfo(OperationTypes appliesWhen) : base(appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - /// appliesWhen;appliesWhen may only be a combination of Insert or Update - public ValidateWithDataErrorInfo(OperationTypes appliesWhen) : base(appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select) || appliesWhen.HasFlag(OperationTypes.Delete)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert or Update"); - } + if (appliesWhen.HasFlag(OperationTypes.Select) || appliesWhen.HasFlag(OperationTypes.Delete)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert or Update"); + } - /// - /// Checks the value for validation errors. - /// - /// The argument value. - public override void CheckValue(object argumentValue) - { - if (argumentValue is IDataErrorInfo validation) - CheckValueCore(validation); - } + /// + /// Checks the value for validation errors. + /// + /// The argument value. + public override void CheckValue(object argumentValue) + { + if (argumentValue is IDataErrorInfo validation) + CheckValueCore(validation); + } - /// - /// Checks the value core. - /// - /// The validation. - /// validation - /// Validation errors: " + errors - protected static void CheckValueCore(IDataErrorInfo validation) - { - if (validation == null) - throw new ArgumentNullException(nameof(validation), $"{nameof(validation)} is null."); + /// + /// Checks the value core. + /// + /// The validation. + /// validation + /// Validation errors: " + errors + protected static void CheckValueCore(IDataErrorInfo validation) + { + if (validation == null) + throw new ArgumentNullException(nameof(validation), $"{nameof(validation)} is null."); - var errors = validation.Error; + var errors = validation.Error; - if (string.IsNullOrEmpty(errors)) - throw new ValidationException($"Validation errors: " + errors); - } + if (string.IsNullOrEmpty(errors)) + throw new ValidationException($"Validation errors: " + errors); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo`1.cs index c79a39891..afca428a6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithDataErrorInfo`1.cs @@ -1,40 +1,39 @@ using System.ComponentModel; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// When this rule is in effect, objects of type T will be checked. +/// Implements the +/// +/// +/// +/// +public class ValidateWithDataErrorInfo : ValidateWithDataErrorInfo + where T : class, IDataErrorInfo { + readonly Action m_ValidationMethod; + /// - /// When this rule is in effect, objects of type T will be checked. - /// Implements the + /// Initializes a new instance of the class. /// - /// - /// - /// - public class ValidateWithDataErrorInfo : ValidateWithDataErrorInfo - where T : class, IDataErrorInfo + /// The rule applies when. + /// The method on the object that triggers validation. Usually this will be something like x => x.Validate(). + public ValidateWithDataErrorInfo(OperationTypes appliesWhen, Action validationMethod) : base(appliesWhen) { - readonly Action m_ValidationMethod; - - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - /// The method on the object that triggers validation. Usually this will be something like x => x.Validate(). - public ValidateWithDataErrorInfo(OperationTypes appliesWhen, Action validationMethod) : base(appliesWhen) - { - m_ValidationMethod = validationMethod; - } + m_ValidationMethod = validationMethod; + } - /// - /// Checks the value for validation errors. - /// - /// The argument value. - public override void CheckValue(object argumentValue) - { - if (!(argumentValue is T validation)) - return; + /// + /// Checks the value for validation errors. + /// + /// The argument value. + public override void CheckValue(object argumentValue) + { + if (!(argumentValue is T validation)) + return; - m_ValidationMethod(validation); - CheckValueCore(validation); - } + m_ValidationMethod(validation); + CheckValueCore(validation); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo.cs index 9bb299a10..c4b5436c4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo.cs @@ -1,50 +1,49 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// When this rule is in effect, objects that implement INotifyDataErrorInfo will be checked. +/// +/// +public class ValidateWithNotifyDataErrorInfo : ValidationRule { /// - /// When this rule is in effect, objects that implement INotifyDataErrorInfo will be checked. + /// Initializes a new instance of the class. /// - /// - public class ValidateWithNotifyDataErrorInfo : ValidationRule + /// The rule applies when. + /// appliesWhen;appliesWhen may only be a combination of Insert or Update + public ValidateWithNotifyDataErrorInfo(OperationTypes appliesWhen) : base(appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - /// appliesWhen;appliesWhen may only be a combination of Insert or Update - public ValidateWithNotifyDataErrorInfo(OperationTypes appliesWhen) : base(appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select) || appliesWhen.HasFlag(OperationTypes.Delete)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert or Update"); - } + if (appliesWhen.HasFlag(OperationTypes.Select) || appliesWhen.HasFlag(OperationTypes.Delete)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert or Update"); + } - /// - /// Checks the value for validation errors. - /// - /// The argument value. - public override void CheckValue(object argumentValue) - { - if (!(argumentValue is INotifyDataErrorInfo validation)) - return; + /// + /// Checks the value for validation errors. + /// + /// The argument value. + public override void CheckValue(object argumentValue) + { + if (!(argumentValue is INotifyDataErrorInfo validation)) + return; - CheckValueCore(validation); - } + CheckValueCore(validation); + } - /// - /// Checks the value core. - /// - /// The validation. - /// - protected static void CheckValueCore(INotifyDataErrorInfo validation) - { - if (validation == null) - throw new ArgumentNullException(nameof(validation), $"{nameof(validation)} is null."); + /// + /// Checks the value core. + /// + /// The validation. + /// + protected static void CheckValueCore(INotifyDataErrorInfo validation) + { + if (validation == null) + throw new ArgumentNullException(nameof(validation), $"{nameof(validation)} is null."); - if (validation.HasErrors) - throw new ValidationException($"Validation errors: " - + string.Join(Environment.NewLine + " ", validation.GetErrors(null).OfType().Select(e => e.ToString()))); - } + if (validation.HasErrors) + throw new ValidationException($"Validation errors: " + + string.Join(Environment.NewLine + " ", validation.GetErrors(null).OfType().Select(e => e.ToString()))); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo`1.cs index 8facf9fb5..2e0455c46 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithNotifyDataErrorInfo`1.cs @@ -1,37 +1,36 @@ using System.ComponentModel; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// When this rule is in effect, objects of type T will be checked. +/// +/// +public class ValidateWithNotifyDataErrorInfo : ValidateWithNotifyDataErrorInfo + where T : class, INotifyDataErrorInfo { + readonly Action m_ValidationMethod; + /// - /// When this rule is in effect, objects of type T will be checked. + /// Initializes a new instance of the class. /// - /// - public class ValidateWithNotifyDataErrorInfo : ValidateWithNotifyDataErrorInfo - where T : class, INotifyDataErrorInfo + /// The rule applies when. + /// The method on the object that triggers validation. Usually this will be something like x => x.Validate(). + public ValidateWithNotifyDataErrorInfo(OperationTypes appliesWhen, Action validationMethod) : base(appliesWhen) { - readonly Action m_ValidationMethod; - - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - /// The method on the object that triggers validation. Usually this will be something like x => x.Validate(). - public ValidateWithNotifyDataErrorInfo(OperationTypes appliesWhen, Action validationMethod) : base(appliesWhen) - { - m_ValidationMethod = validationMethod; - } + m_ValidationMethod = validationMethod; + } - /// - /// Checks the value for validation errors. - /// - /// The argument value. - public override void CheckValue(object argumentValue) - { - if (!(argumentValue is T validation)) - return; + /// + /// Checks the value for validation errors. + /// + /// The argument value. + public override void CheckValue(object argumentValue) + { + if (!(argumentValue is T validation)) + return; - m_ValidationMethod(validation); - CheckValueCore(validation); - } + m_ValidationMethod(validation); + CheckValueCore(validation); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithValidatable.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithValidatable.cs index dbdd96c11..48d878d16 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithValidatable.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidateWithValidatable.cs @@ -2,43 +2,42 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor.ComponentModel; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// When this rule is in effect, objects that implement IValidatable will be checked. +/// +/// +[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Validatable")] +public class ValidateWithValidatable : ValidationRule { /// - /// When this rule is in effect, objects that implement IValidatable will be checked. + /// Initializes a new instance of the class. /// - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Validatable")] - public class ValidateWithValidatable : ValidationRule + /// The rule applies when. + /// appliesWhen;appliesWhen may only be a combination of Insert or Update + public ValidateWithValidatable(OperationTypes appliesWhen) : base(appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - /// appliesWhen;appliesWhen may only be a combination of Insert or Update - public ValidateWithValidatable(OperationTypes appliesWhen) : base(appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select) || appliesWhen.HasFlag(OperationTypes.Delete)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert or Update"); - } + if (appliesWhen.HasFlag(OperationTypes.Select) || appliesWhen.HasFlag(OperationTypes.Delete)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert or Update"); + } - /// - /// Checks the value for validation errors. - /// - /// The argument value. - /// - public override void CheckValue(object argumentValue) - { - if (!(argumentValue is IValidatable validation)) - return; + /// + /// Checks the value for validation errors. + /// + /// The argument value. + /// + public override void CheckValue(object argumentValue) + { + if (!(argumentValue is IValidatable validation)) + return; - validation.Validate(); - if (!validation.HasErrors) - return; + validation.Validate(); + if (!validation.HasErrors) + return; - throw new ValidationException($"Validation errors: " - + Environment.NewLine - + string.Join(Environment.NewLine + "\t", validation.GetAllErrors().Select(e => e.ToString()))); - } + throw new ValidationException($"Validation errors: " + + Environment.NewLine + + string.Join(Environment.NewLine + "\t", validation.GetAllErrors().Select(e => e.ToString()))); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidationRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidationRule.cs index c7988419b..18dea574e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidationRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValidationRule.cs @@ -1,26 +1,25 @@ using System.ComponentModel.DataAnnotations; -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// Base class for validation style rules. +/// +/// +public abstract class ValidationRule : AuditRule { /// - /// Base class for validation style rules. + /// Initializes a new instance of the class. /// - /// - public abstract class ValidationRule : AuditRule + /// The rule applies when. + protected ValidationRule(OperationTypes appliesWhen) : base(appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// The rule applies when. - protected ValidationRule(OperationTypes appliesWhen) : base(appliesWhen) - { - } - - /// - /// Checks the value for validation errors. - /// - /// The argument value. - /// A ValidationException will be thrown if the object contains validation errors. - public abstract void CheckValue(object argumentValue); } + + /// + /// Checks the value for validation errors. + /// + /// The argument value. + /// A ValidationException will be thrown if the object contains validation errors. + public abstract void CheckValue(object argumentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValueRule.cs b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValueRule.cs index 8731cb2df..fd38214f3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValueRule.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/AuditRules/ValueRule.cs @@ -1,59 +1,58 @@ -namespace Tortuga.Chain.AuditRules +namespace Tortuga.Chain.AuditRules; + +/// +/// Applies the indicated value to the column, overriding any previously applied value. +/// +/// +public class ValueRule : ColumnRule { /// - /// Applies the indicated value to the column, overriding any previously applied value. + /// Initializes a new instance of the class. /// - /// - public class ValueRule : ColumnRule + /// Name of the column. + /// The value to apply. + /// The rule can be applied to insert, update, and/or soft delete operations. + /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete + /// + /// This will have no effect on hard deletes. + /// + public ValueRule(string columnName, object value, OperationTypes appliesWhen) : base(columnName, appliesWhen) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// The value to apply. - /// The rule can be applied to insert, update, and/or soft delete operations. - /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete - /// - /// This will have no effect on hard deletes. - /// - public ValueRule(string columnName, object value, OperationTypes appliesWhen) : base(columnName, appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); + if (appliesWhen.HasFlag(OperationTypes.Select)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); - ValueFactory = (_, __, ___) => value; - } + ValueFactory = (_, __, ___) => value; + } - /// - /// Initializes a new instance of the class. - /// - /// Name of the column. - /// The value factory. - /// The applies when. - /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete - public ValueRule(string columnName, ColumnValueGenerator valueFactory, OperationTypes appliesWhen) : base(columnName, appliesWhen) - { - if (appliesWhen.HasFlag(OperationTypes.Select)) - throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); + /// + /// Initializes a new instance of the class. + /// + /// Name of the column. + /// The value factory. + /// The applies when. + /// appliesWhen;appliesWhen may only be a combination of Insert, Update, or Delete + public ValueRule(string columnName, ColumnValueGenerator valueFactory, OperationTypes appliesWhen) : base(columnName, appliesWhen) + { + if (appliesWhen.HasFlag(OperationTypes.Select)) + throw new ArgumentOutOfRangeException(nameof(appliesWhen), appliesWhen, "appliesWhen may only be a combination of Insert, Update, or Delete"); - ValueFactory = valueFactory; - } + ValueFactory = valueFactory; + } - /// - /// Gets the value factory. - /// - /// - /// The value factory. - /// - public ColumnValueGenerator ValueFactory { get; } + /// + /// Gets the value factory. + /// + /// + /// The value factory. + /// + public ColumnValueGenerator ValueFactory { get; } - /// - /// Generates the value to be used for the operation. - /// - /// The argument value. - /// The user value. - /// The current value. Used when the rule is conditionally applied. - /// - public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) => ValueFactory(argumentValue, userValue, currentValue); - } + /// + /// Generates the value to be used for the operation. + /// + /// The argument value. + /// The user value. + /// The current value. Used when the rule is conditionally applied. + /// + public override object GenerateValue(object? argumentValue, object? userValue, object? currentValue) => ValueFactory(argumentValue, userValue, currentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CachePolicy.cs b/Tortuga.Chain/Tortuga.Chain.Core/CachePolicy.cs index d1a74f794..a9d278195 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CachePolicy.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CachePolicy.cs @@ -1,38 +1,37 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class CachePolicy. +/// +public class CachePolicy { /// - /// Class CachePolicy. + /// Initializes a new instance of the class. /// - public class CachePolicy + /// The absolute expiration. + public CachePolicy(DateTimeOffset absoluteExpiration) { - /// - /// Initializes a new instance of the class. - /// - /// The absolute expiration. - public CachePolicy(DateTimeOffset absoluteExpiration) - { - AbsoluteExpiration = absoluteExpiration; - } + AbsoluteExpiration = absoluteExpiration; + } - /// - /// Initializes a new instance of the class. - /// - /// The sliding expiration. - public CachePolicy(TimeSpan slidingExpiration) - { - SlidingExpiration = slidingExpiration; - } + /// + /// Initializes a new instance of the class. + /// + /// The sliding expiration. + public CachePolicy(TimeSpan slidingExpiration) + { + SlidingExpiration = slidingExpiration; + } - /// - /// Gets or sets the absolute expiration. - /// - /// The absolute expiration. - public DateTimeOffset? AbsoluteExpiration { get; private set; } + /// + /// Gets or sets the absolute expiration. + /// + /// The absolute expiration. + public DateTimeOffset? AbsoluteExpiration { get; private set; } - /// - /// Gets or sets the sliding expiration. - /// - /// The sliding expiration. - public TimeSpan? SlidingExpiration { get; private set; } - } + /// + /// Gets or sets the sliding expiration. + /// + /// The sliding expiration. + public TimeSpan? SlidingExpiration { get; private set; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/ChainInternalException.cs b/Tortuga.Chain/Tortuga.Chain.Core/ChainInternalException.cs index c71a25190..2365a2016 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/ChainInternalException.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/ChainInternalException.cs @@ -1,48 +1,46 @@ -using System; -using System.Runtime.Serialization; +using System.Runtime.Serialization; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This exception occurs when there is an internal error in the Chain library. This is a bug in Chain itself or one of its extensions. +/// +[Serializable] +public class ChainInternalException : Exception { /// - /// This exception occurs when there is an internal error in the Chain library. This is a bug in Chain itself or one of its extensions. + /// Initializes a new instance of the class. /// - [Serializable] - public class ChainInternalException : Exception + public ChainInternalException() { - /// - /// Initializes a new instance of the class. - /// - public ChainInternalException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public ChainInternalException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public ChainInternalException(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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. - public ChainInternalException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// 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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. + public ChainInternalException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The data necessary to serialize or deserialize an object. - /// Description of the source and destination of the specified serialized stream. - protected ChainInternalException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The data necessary to serialize or deserialize an object. + /// Description of the source and destination of the specified serialized stream. + protected ChainInternalException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CollectionOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/CollectionOptions.cs index f1dc15c78..0927a0d87 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CollectionOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CollectionOptions.cs @@ -1,21 +1,20 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Indicates how the collection will be generated from a result set. +/// +[Flags] +public enum CollectionOptions { /// - /// Indicates how the collection will be generated from a result set. + /// Use the default behavior. /// - [Flags] - public enum CollectionOptions - { - /// - /// Use the default behavior. - /// - /// If a class has more than one constructor, the default constructor will be used. - None = 0, + /// If a class has more than one constructor, the default constructor will be used. + None = 0, - /// - /// Infer which non-default constructor to use. When this option is chosen, individual properties will not be set. - /// - /// This will throw an error unless there is exactly one public, non-default constructor. - InferConstructor = 8, - } + /// + /// Infer which non-default constructor to use. When this option is chosen, individual properties will not be set. + /// + /// This will throw an error unless there is exactly one public, non-default constructor. + InferConstructor = 8, } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder.cs index 5d7f2e62a..d063fe674 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder.cs @@ -1,69 +1,66 @@ using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the non-generic version of the base class from which all other command builders are created. +/// +/// +public abstract class DbCommandBuilder : IDbCommandBuilder { /// - /// This is the non-generic version of the base class from which all other command builders are created. + /// Gets or sets a value indicating whether or not to use CommandBehavior.SequentialAccess. /// - /// - public abstract class DbCommandBuilder : IDbCommandBuilder - { - /// - /// Gets or sets a value indicating whether strict mode is enabled. - /// - /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. - internal protected bool StrictMode { get; internal set; } - - - /// - /// Gets or sets a value indicating whether or not to use CommandBehavior.SequentialAccess. - /// - internal protected bool SequentialAccessMode { get; internal set; } + internal protected bool SequentialAccessMode { get; internal set; } + /// + /// Gets or sets a value indicating whether strict mode is enabled. + /// + /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. + internal protected bool StrictMode { get; internal set; } - /// - /// Indicates this operation has no result set. - /// - /// - public abstract ILink AsNonQuery(); + /// + /// Indicates this operation has no result set. + /// + /// + public abstract ILink AsNonQuery(); - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - public int? Execute(object? state = null) => AsNonQuery().Execute(state); + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + public int? Execute(object? state = null) => AsNonQuery().Execute(state); - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// Task. - public Task ExecuteAsync(object? state = null) => AsNonQuery().ExecuteAsync(state); + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// Task. + public Task ExecuteAsync(object? state = null) => AsNonQuery().ExecuteAsync(state); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task. - public Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - return AsNonQuery().ExecuteAsync(cancellationToken, state); - } + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task. + public Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + return AsNonQuery().ExecuteAsync(cancellationToken, state); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// If the column name was not found, this will return null - /// - public abstract ColumnMetadata? TryGetColumn(string columnName); + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// If the column name was not found, this will return null + /// + public abstract ColumnMetadata? TryGetColumn(string columnName); - /// - /// Returns a list of columns known to be non-nullable. - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// This is used by materializers to skip IsNull checks. - public abstract IReadOnlyList TryGetNonNullableColumns(); - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// This is used by materializers to skip IsNull checks. + public abstract IReadOnlyList TryGetNonNullableColumns(); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder`2.cs index 45d39b897..90e57b425 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbCommandBuilder`2.cs @@ -4,46 +4,45 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class from which all other command builders are created. +/// +/// The type of the command used. +/// The type of the t parameter type. +public abstract class DbCommandBuilder : DbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// This is the base class from which all other command builders are created. - /// - /// The type of the command used. - /// The type of the t parameter type. - public abstract class DbCommandBuilder : DbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter + /// Initializes a new instance of the class. + /// The data source. + /// dataSource + protected DbCommandBuilder(ICommandDataSource dataSource) { - /// Initializes a new instance of the class. - /// The data source. - /// dataSource - protected DbCommandBuilder(ICommandDataSource dataSource) - { - DataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - StrictMode = dataSource.StrictMode; - SequentialAccessMode = dataSource.SequentialAccessMode; - } + DataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + StrictMode = dataSource.StrictMode; + SequentialAccessMode = dataSource.SequentialAccessMode; + } - /// - /// Gets the data source. - /// - /// The data source. - [EditorBrowsable(EditorBrowsableState.Never)] - public ICommandDataSource DataSource { get; } + /// + /// Gets the data source. + /// + /// The data source. + [EditorBrowsable(EditorBrowsableState.Never)] + public ICommandDataSource DataSource { get; } - /// - /// Indicates this operation has no result set. - /// - /// - public override sealed ILink AsNonQuery() { return new NonQueryMaterializer(this); } + /// + /// Indicates this operation has no result set. + /// + /// + public override sealed ILink AsNonQuery() { return new NonQueryMaterializer(this); } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - [EditorBrowsable(EditorBrowsableState.Never)] - public abstract CommandExecutionToken Prepare(Materializer materializer); - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + [EditorBrowsable(EditorBrowsableState.Never)] + public abstract CommandExecutionToken Prepare(Materializer materializer); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbOperationBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbOperationBuilder`2.cs index c4c950a32..080d76cd8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbOperationBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/DbOperationBuilder`2.cs @@ -5,74 +5,73 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class from which all other operation builders are created. +/// +/// The type of the t connection. +/// The type of the t transaction. +/// +public abstract class DbOperationBuilder : DbCommandBuilder + where TConnection : DbConnection + where TTransaction : DbTransaction { /// - /// This is the base class from which all other operation builders are created. + /// Initializes a new instance of the class. /// - /// The type of the t connection. - /// The type of the t transaction. - /// - public abstract class DbOperationBuilder : DbCommandBuilder - where TConnection : DbConnection - where TTransaction : DbTransaction + /// The data source. + /// dataSource + protected DbOperationBuilder(IOperationDataSource dataSource) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// dataSource - protected DbOperationBuilder(IOperationDataSource dataSource) - { - DataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - StrictMode = dataSource.StrictMode; - SequentialAccessMode = dataSource.SequentialAccessMode; - } + DataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + StrictMode = dataSource.StrictMode; + SequentialAccessMode = dataSource.SequentialAccessMode; + } - /// - /// Gets the data source. - /// - /// The data source. - [EditorBrowsable(EditorBrowsableState.Never)] - public IOperationDataSource DataSource { get; } + /// + /// Gets the data source. + /// + /// The data source. + [EditorBrowsable(EditorBrowsableState.Never)] + public IOperationDataSource DataSource { get; } - /// - /// Indicates this operation has no result set. - /// - /// ILink<System.Nullable<System.Int32>>. - public override ILink AsNonQuery() => new Operation(this); + /// + /// Indicates this operation has no result set. + /// + /// ILink<System.Nullable<System.Int32>>. + public override ILink AsNonQuery() => new Operation(this); - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// ExecutionToken<TCommand>. - public abstract OperationExecutionToken Prepare(); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// ExecutionToken<TCommand>. + public abstract OperationExecutionToken Prepare(); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => null; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => null; - /// - /// Implementation the specified operation. - /// - /// The connection. - /// The transaction. - /// System.Nullable<System.Int32>. - protected internal abstract int? Implementation(TConnection connection, TTransaction? transaction); + /// + /// Implementation the specified operation. + /// + /// The connection. + /// The transaction. + /// System.Nullable<System.Int32>. + protected internal abstract int? Implementation(TConnection connection, TTransaction? transaction); - /// - /// Implementation the specified operation. - /// - /// The connection. - /// The transaction. - /// The cancellation token. - /// Task<System.Nullable<System.Int32>>. - protected internal abstract Task ImplementationAsync(TConnection connection, TTransaction? transaction, CancellationToken cancellationToken); - } + /// + /// Implementation the specified operation. + /// + /// The connection. + /// The transaction. + /// The cancellation token. + /// Task<System.Nullable<System.Int32>>. + protected internal abstract Task ImplementationAsync(TConnection connection, TTransaction? transaction, CancellationToken cancellationToken); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/GenericDbSqlCall.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/GenericDbSqlCall.cs index cbd90a0d4..2fd972a12 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/GenericDbSqlCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/GenericDbSqlCall.cs @@ -5,66 +5,65 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +[SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] +class GenericDbSqlCall : MultipleTableDbCommandBuilder { - [SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] - class GenericDbSqlCall : MultipleTableDbCommandBuilder - { - readonly object? m_ArgumentValue; - readonly GenericDbDataSource m_DataSource; - readonly string m_SqlStatement; + readonly object? m_ArgumentValue; + readonly GenericDbDataSource m_DataSource; + readonly string m_SqlStatement; - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The SQL statement. - /// The argument value. - /// sqlStatement is null or empty.;sqlStatement - /// sqlStatement is null or empty.;sqlStatement - public GenericDbSqlCall(GenericDbDataSource dataSource, string sqlStatement, object? argumentValue) : base(dataSource) - { - if (string.IsNullOrEmpty(sqlStatement)) - throw new ArgumentException("sqlStatement is null or empty.", nameof(sqlStatement)); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// The SQL statement. + /// The argument value. + /// sqlStatement is null or empty.;sqlStatement + /// sqlStatement is null or empty.;sqlStatement + public GenericDbSqlCall(GenericDbDataSource dataSource, string sqlStatement, object? argumentValue) : base(dataSource) + { + if (string.IsNullOrEmpty(sqlStatement)) + throw new ArgumentException("sqlStatement is null or empty.", nameof(sqlStatement)); - m_SqlStatement = sqlStatement; - m_ArgumentValue = argumentValue; - m_DataSource = dataSource; - } + m_SqlStatement = sqlStatement; + m_ArgumentValue = argumentValue; + m_DataSource = dataSource; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - var parameters = SqlBuilder.GetParameters(m_ArgumentValue, () => m_DataSource.CreateParameter()); - return new CommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, parameters); - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + var parameters = SqlBuilder.GetParameters(m_ArgumentValue, () => m_DataSource.CreateParameter()); + return new CommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, parameters); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => null; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => null; - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() - { - return ImmutableList.Empty; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() + { + return ImmutableList.Empty; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IDbCommandBuilder.cs index 6e2a78f26..17ba96f66 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IDbCommandBuilder.cs @@ -1,46 +1,45 @@ using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This allows executing command builders without returning anything. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. +public interface IDbCommandBuilder { /// - /// This allows executing command builders without returning anything. + /// Indicates this operation has no result set. /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. - public interface IDbCommandBuilder - { - /// - /// Indicates this operation has no result set. - /// - /// This may contain the result code or number of rows affected. - ILink AsNonQuery(); + /// This may contain the result code or number of rows affected. + ILink AsNonQuery(); - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - int? Execute(object? state = null); + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + int? Execute(object? state = null); - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// Task. - Task ExecuteAsync(object? state = null); + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// Task. + Task ExecuteAsync(object? state = null); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task. - Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task. + Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// If the column name was not found, this will return null - ColumnMetadata? TryGetColumn(string columnName); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// If the column name was not found, this will return null + ColumnMetadata? TryGetColumn(string columnName); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder.cs index 68723f1e5..57e8c79d4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder.cs @@ -2,735 +2,734 @@ using System.Diagnostics.CodeAnalysis; using System.Xml.Linq; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This allows the use of multi-row materializers against a command builder. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. +public interface IMultipleRowDbCommandBuilder : ISingleRowDbCommandBuilder { /// - /// This allows the use of multi-row materializers against a command builder. - /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. - public interface IMultipleRowDbCommandBuilder : ISingleRowDbCommandBuilder - { - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToBooleanList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// The list options. - /// - ILink> ToBooleanList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToByteArrayList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// The list options. - /// - ILink> ToByteArrayList(ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The collection options. - /// - IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class; - - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The type of the collection. - /// The collection options. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - IConstructibleMaterializer ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class - where TCollection : ICollection, new(); - - /// - /// Indicates the results should be materialized as a DataSet. - /// - ILink ToDataTable(); - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// The list options. - /// - ILink> ToDateTimeList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDateTimeList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// The list options. - /// - ILink> ToDateTimeOffsetList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDateTimeOffsetList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of DateTimeOffset. - /// - /// The list options. - /// - ILink> ToDateTimeOffsetSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of DateTimeOffset. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDateTimeOffsetSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of DateTime. - /// - /// The list options. - /// - ILink> ToDateTimeSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of DateTime. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDateTimeSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - ILink> ToDecimalList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDecimalList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// The list options. - /// - ILink> ToDecimalSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDecimalSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key column. - /// The dictionary options. - /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. - IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class; - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The type of dictionary. - /// The key column. - /// The dictionary options. - /// IConstructibleMaterializer<TDictionary>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - IConstructibleMaterializer ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - where TDictionary : IDictionary, new(); - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key function. - /// The dictionary options. - /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. - IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class; - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The type of dictionary. - /// The key function. - /// The dictionary options. - /// IConstructibleMaterializer<TDictionary>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - IConstructibleMaterializer ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - where TDictionary : IDictionary, new(); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - ILink> ToDoubleList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDoubleList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// The list options. - /// - ILink> ToDoubleSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDoubleSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a list of dynamically typed objects. - /// - /// - ILink> ToDynamicCollection(); - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// The list options. - /// - ILink> ToGuidList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToGuidList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of Guids. - /// - /// The list options. - /// - ILink> ToGuidSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of Guids. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToGuidSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as an immutable array of objects. - /// - /// The type of the model. - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. - IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) + /// Indicates the results should be materialized as a list of booleans. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToBooleanList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of booleans. + /// + /// The list options. + /// + ILink> ToBooleanList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of booleans. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToBooleanOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of booleans. + /// + /// The list options. + /// + ILink> ToBooleanOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToByteArrayList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// The list options. + /// + ILink> ToByteArrayList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToByteArrayOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// The list options. + /// + ILink> ToByteArrayOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The collection options. + /// + IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class; + + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The type of the collection. + /// The collection options. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + IConstructibleMaterializer ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class + where TCollection : ICollection, new(); + + /// + /// Indicates the results should be materialized as a DataSet. + /// + ILink ToDataTable(); + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// The list options. + /// + ILink> ToDateTimeList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDateTimeList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// The list options. + /// + ILink> ToDateTimeOffsetList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDateTimeOffsetList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// The list options. + /// + ILink> ToDateTimeOffsetOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDateTimeOffsetOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of DateTimeOffset. + /// + /// The list options. + /// + ILink> ToDateTimeOffsetSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of DateTimeOffset. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDateTimeOffsetSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// The list options. + /// + ILink> ToDateTimeOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDateTimeOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of DateTime. + /// + /// The list options. + /// + ILink> ToDateTimeSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of DateTime. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDateTimeSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + ILink> ToDecimalList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDecimalList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + ILink> ToDecimalOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDecimalOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// The list options. + /// + ILink> ToDecimalSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDecimalSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key column. + /// The dictionary options. + /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. + IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class; + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The type of dictionary. + /// The key column. + /// The dictionary options. + /// IConstructibleMaterializer<TDictionary>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + IConstructibleMaterializer ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + where TDictionary : IDictionary, new(); + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key function. + /// The dictionary options. + /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. + IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class; + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The type of dictionary. + /// The key function. + /// The dictionary options. + /// IConstructibleMaterializer<TDictionary>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + IConstructibleMaterializer ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + where TDictionary : IDictionary, new(); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + ILink> ToDoubleList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDoubleList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + ILink> ToDoubleOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDoubleOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// The list options. + /// + ILink> ToDoubleSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToDoubleSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a list of dynamically typed objects. + /// + /// + ILink> ToDynamicCollection(); + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// The list options. + /// + ILink> ToGuidList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToGuidList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// The list options. + /// + ILink> ToGuidOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToGuidOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of Guids. + /// + /// The list options. + /// + ILink> ToGuidSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of Guids. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToGuidSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as an immutable array of objects. + /// + /// The type of the model. + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. + IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) where TObject : class; - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key function. - /// The dictionary options. - /// - IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class; - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key column. - /// The dictionary options. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class; - - /// - /// Materializes the result as an immutable list of objects. - /// - /// The type of the model. - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. - IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class; - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - ILink> ToInt16List(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt16List(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// The list options. - /// - ILink> ToInt16Set(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt16Set(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - ILink> ToInt32List(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt32List(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// The list options. - /// - ILink> ToInt32Set(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt32Set(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - ILink> ToInt64List(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt64List(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// The list options. - /// - ILink> ToInt64Set(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt64Set(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - ILink> ToSingleList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToSingleList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// The list options. - /// - ILink> ToSingleSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToSingleSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// The list options. - /// - ILink> ToStringList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToStringList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of strings. - /// - /// The list options. - /// - ILink> ToStringSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of strings. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToStringSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a Table. - /// - ILink ToTable(); - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// The list options. - /// - ILink> ToTimeSpanList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToTimeSpanList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of TimeSpan. - /// - /// The list options. - /// - ILink> ToTimeSpanSet(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a set of TimeSpan. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToTimeSpanSet(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a list of XElement. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - ILink> ToXmlList(ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a list of XElement. - /// - /// Name of the column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - ILink> ToXmlList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToBooleanOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// The list options. - /// - ILink> ToBooleanOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToByteArrayOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// The list options. - /// - ILink> ToByteArrayOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// The list options. - /// - ILink> ToDateTimeOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDateTimeOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// The list options. - /// - ILink> ToDateTimeOffsetOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDateTimeOffsetOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - ILink> ToDecimalOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDecimalOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - ILink> ToDoubleOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToDoubleOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// The list options. - /// - ILink> ToGuidOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToGuidOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - ILink> ToInt16OrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt16OrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - ILink> ToInt32OrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt32OrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - ILink> ToInt64OrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToInt64OrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - ILink> ToSingleOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToSingleOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// The list options. - /// - ILink> ToStringOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToStringOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// The list options. - /// - ILink> ToTimeSpanOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// Name of the desired column. - /// The list options. - /// - ILink> ToTimeSpanOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a list of XElement. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - ILink> ToXmlOrNullList(ListOptions listOptions = ListOptions.None); - - /// - /// Materializes the result as a list of XElement. - /// - /// Name of the column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - ILink> ToXmlOrNullList(string columnName, ListOptions listOptions = ListOptions.None); - } + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key function. + /// The dictionary options. + /// + IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class; + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key column. + /// The dictionary options. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class; + + /// + /// Materializes the result as an immutable list of objects. + /// + /// The type of the model. + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. + IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class; + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + ILink> ToInt16List(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt16List(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + ILink> ToInt16OrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt16OrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// The list options. + /// + ILink> ToInt16Set(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt16Set(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + ILink> ToInt32List(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt32List(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + ILink> ToInt32OrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt32OrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// The list options. + /// + ILink> ToInt32Set(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt32Set(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + ILink> ToInt64List(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt64List(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + ILink> ToInt64OrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt64OrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// The list options. + /// + ILink> ToInt64Set(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToInt64Set(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + ILink> ToSingleList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToSingleList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + ILink> ToSingleOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToSingleOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// The list options. + /// + ILink> ToSingleSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToSingleSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// The list options. + /// + ILink> ToStringList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToStringList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// The list options. + /// + ILink> ToStringOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToStringOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of strings. + /// + /// The list options. + /// + ILink> ToStringSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of strings. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToStringSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a Table. + /// + ILink
ToTable(); + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// The list options. + /// + ILink> ToTimeSpanList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToTimeSpanList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// The list options. + /// + ILink> ToTimeSpanOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToTimeSpanOrNullList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of TimeSpan. + /// + /// The list options. + /// + ILink> ToTimeSpanSet(ListOptions listOptions = ListOptions.None); + + /// + /// Indicates the results should be materialized as a set of TimeSpan. + /// + /// Name of the desired column. + /// The list options. + /// + ILink> ToTimeSpanSet(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a list of XElement. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + ILink> ToXmlList(ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a list of XElement. + /// + /// Name of the column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + ILink> ToXmlList(string columnName, ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a list of XElement. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + ILink> ToXmlOrNullList(ListOptions listOptions = ListOptions.None); + + /// + /// Materializes the result as a list of XElement. + /// + /// Name of the column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + ILink> ToXmlOrNullList(string columnName, ListOptions listOptions = ListOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder`1.cs index b9a7814bb..22c440e00 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleRowDbCommandBuilder`1.cs @@ -1,79 +1,78 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This allows the use of multi-row materializers against a command builder. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. +public interface IMultipleRowDbCommandBuilder : IMultipleRowDbCommandBuilder, ISingleRowDbCommandBuilder + where TObject : class { /// - /// This allows the use of multi-row materializers against a command builder. + /// Materializes the result as a list of objects. /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. - public interface IMultipleRowDbCommandBuilder : IMultipleRowDbCommandBuilder, ISingleRowDbCommandBuilder - where TObject : class - { - /// - /// Materializes the result as a list of objects. - /// - /// The collection options. - /// - IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None); + /// The collection options. + /// + IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None); - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The key column. - /// The dictionary options. - /// - IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull; + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The key column. + /// The dictionary options. + /// + IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull; - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The key function. - /// The dictionary options. - /// - IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull; + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The key function. + /// The dictionary options. + /// + IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull; - /// - /// Materializes the result as an immutable array of objects. - /// - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. - IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None); + /// + /// Materializes the result as an immutable array of objects. + /// + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. + IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None); - /// - /// Materializes the result as an immutable list of objects. - /// - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. - IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None); + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The key function. + /// The dictionary options. + /// + IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull; - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The key function. - /// The dictionary options. - /// - IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull; + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The key column. + /// The dictionary options. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull; - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The key column. - /// The dictionary options. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull; - } + /// + /// Materializes the result as an immutable list of objects. + /// + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. + IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleTableDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleTableDbCommandBuilder.cs index 748253169..ac65c704b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleTableDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IMultipleTableDbCommandBuilder.cs @@ -1,72 +1,71 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This command builder may return multiple record sets +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. +public interface IMultipleTableDbCommandBuilder : IMultipleRowDbCommandBuilder { /// - /// This command builder may return multiple record sets + /// To the collection set. /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. - public interface IMultipleTableDbCommandBuilder : IMultipleRowDbCommandBuilder - { - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// - ILink, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new(); + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// + ILink, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new(); - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// The type of the 3rd collection. - /// - ILink, List, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - where T3 : class, new(); + /// + /// To the collection set. + /// + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// The type of the 3rd collection. + /// + ILink, List, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() + where T3 : class, new(); - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// The type of the 3rd collection. - /// The type of the 4th collection. - /// - ILink, List, List, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - where T4 : class, new(); + /// + /// To the collection set. + /// + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// The type of the 3rd collection. + /// The type of the 4th collection. + /// + ILink, List, List, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + where T4 : class, new(); - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// The type of the 3rd collection. - /// The type of the 4th collection. - /// The type of the 5th collection. - /// - ILink, List, List, List, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - where T4 : class, new() - where T5 : class, new(); + /// + /// To the collection set. + /// + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// The type of the 3rd collection. + /// The type of the 4th collection. + /// The type of the 5th collection. + /// + ILink, List, List, List, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + where T4 : class, new() + where T5 : class, new(); - /// - /// Indicates the results should be materialized as a DataSet. - /// - /// The table names. - ILink ToDataSet(params string[] tableNames); + /// + /// Indicates the results should be materialized as a DataSet. + /// + /// The table names. + ILink ToDataSet(params string[] tableNames); - /// - /// Indicates the results should be materialized as a set of tables. - /// - ILink ToTableSet(params string[] tableNames); - } + /// + /// Indicates the results should be materialized as a set of tables. + /// + ILink ToTableSet(params string[] tableNames); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IObjectDbCommandBuilder`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IObjectDbCommandBuilder`1.cs index 67b804a59..424f199b6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IObjectDbCommandBuilder`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IObjectDbCommandBuilder`1.cs @@ -1,45 +1,44 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This represents command builders that operate on single object parameters: Insert, Update, Upsert, Delete +/// +/// The type of the argument. +public interface IObjectDbCommandBuilder : ISingleRowDbCommandBuilder + where TArgument : class { /// - /// This represents command builders that operate on single object parameters: Insert, Update, Upsert, Delete + /// Gets the argument value passed to the command builder. /// - /// The type of the argument. - public interface IObjectDbCommandBuilder : ISingleRowDbCommandBuilder - where TArgument : class - { - /// - /// Gets the argument value passed to the command builder. - /// - /// The argument value. - TArgument ArgumentValue { get; } + /// The argument value. + TArgument ArgumentValue { get; } - /// - /// Materializes the result as a new instance of the same type as the argumentValue - /// - /// The row options. - /// - /// To update the argumentValue itself, use WithRefresh() instead. - ILink ToObject(RowOptions rowOptions = RowOptions.None); + /// + /// Materializes the result as a new instance of the same type as the argumentValue + /// + /// The row options. + /// + /// To update the argumentValue itself, use WithRefresh() instead. + ILink ToObject(RowOptions rowOptions = RowOptions.None); - /// - /// Materializes the result as a new instance of the same type as the argumentValue - /// - /// The row options. - /// - /// To update the argumentValue itself, use WithRefresh() instead. - ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None); + /// + /// Materializes the result as a new instance of the same type as the argumentValue + /// + /// The row options. + /// + /// To update the argumentValue itself, use WithRefresh() instead. + ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None); - /// - /// Uses an explicitly specified set of key column(s). This overrides the UseKeyAttribute option. - /// - /// The column names that form a unique key. - /// - IObjectDbCommandBuilder WithKeys(params string[] columnNames); + /// + /// Uses an explicitly specified set of key column(s). This overrides the UseKeyAttribute option. + /// + /// The column names that form a unique key. + /// + IObjectDbCommandBuilder WithKeys(params string[] columnNames); - /// - /// After executing the operation, refreshes the properties on the argumentValue by reading the updated values from the database. - /// - /// - ILink WithRefresh(); - } + /// + /// After executing the operation, refreshes the properties on the argumentValue by reading the updated values from the database. + /// + /// + ILink WithRefresh(); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IProcedureCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IProcedureCommandBuilder.cs index 0d6991c46..725a8bd91 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IProcedureCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IProcedureCommandBuilder.cs @@ -1,23 +1,22 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This command builder can capture output parameters. +/// +public interface IProcedureDbCommandBuilder : IMultipleTableDbCommandBuilder { /// - /// This command builder can capture output parameters. + /// Captures the output parameters as a dictionary. /// - public interface IProcedureDbCommandBuilder : IMultipleTableDbCommandBuilder - { - /// - /// Captures the output parameters as a dictionary. - /// - /// The output parameters as a dictionary. - /// This will throw an exception if there are no output parameters. - ILink> AsOutputs(); + /// The output parameters as a dictionary. + /// This will throw an exception if there are no output parameters. + ILink> AsOutputs(); - /// - /// Captures the output parameters and use them to populate a new object. - /// - /// The type that will hold the output parameters. - /// The output parameters as an object. - /// This will throw an exception if there are no output parameters. - ILink AsOutputs() where TObject : class, new(); - } + /// + /// Captures the output parameters and use them to populate a new object. + /// + /// The type that will hold the output parameters. + /// The output parameters as an object. + /// This will throw an exception if there are no output parameters. + ILink AsOutputs() where TObject : class, new(); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IScalarDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IScalarDbCommandBuilder.cs index 7c91f3729..6cccff4ff 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IScalarDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IScalarDbCommandBuilder.cs @@ -1,310 +1,309 @@ using System.Xml.Linq; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This allows the use of scalar materializers against a command builder. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. +public interface IScalarDbCommandBuilder : IDbCommandBuilder { /// - /// This allows the use of scalar materializers against a command builder. - /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. - public interface IScalarDbCommandBuilder : IDbCommandBuilder - { - /// - /// Indicates the results should be materialized as a Boolean. - /// - ILink ToBoolean(); - - /// - /// Indicates the results should be materialized as a Boolean. - /// - /// Name of the desired column. - ILink ToBoolean(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Boolean. - /// - ILink ToBooleanOrNull(); - - /// - /// Indicates the results should be materialized as a nullable Boolean. - /// - /// Name of the desired column. - ILink ToBooleanOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a byte. - /// - ILink ToByte(); - - /// - /// Indicates the results should be materialized as a byte. - /// - /// Name of the desired column. - ILink ToByte(string columnName); - - /// - /// Indicates the results should be materialized as a byte array. - /// - ILink ToByteArray(); - - /// - /// Indicates the results should be materialized as a byte array. - /// - /// Name of the desired column. - ILink ToByteArray(string columnName); - - /// - /// Indicates the results should be materialized as a nullable byte. - /// - ILink ToByteOrNull(); - - /// - /// Indicates the results should be materialized as a nullable byte. - /// - /// Name of the desired column. - ILink ToByteOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a DateTime. - /// - ILink ToDateTime(); - - /// - /// Indicates the results should be materialized as a DateTime. - /// - /// Name of the desired column. - ILink ToDateTime(string columnName); - - /// - /// Indicates the results should be materialized as a DateTimeOffset. - /// - ILink ToDateTimeOffset(); - - /// - /// Indicates the results should be materialized as a DateTimeOffset. - /// - /// Name of the desired column. - ILink ToDateTimeOffset(string columnName); - - /// - /// Indicates the results should be materialized as a nullable DateTimeOffset. - /// - ILink ToDateTimeOffsetOrNull(); - - /// - /// Indicates the results should be materialized as a nullable DateTimeOffset. - /// - /// Name of the desired column. - ILink ToDateTimeOffsetOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a nullable DateTime. - /// - ILink ToDateTimeOrNull(); - - /// - /// Indicates the results should be materialized as a nullable DateTime. - /// - /// Name of the desired column. - ILink ToDateTimeOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Decimal. - /// - ILink ToDecimal(); - - /// - /// Indicates the results should be materialized as a Decimal. - /// - /// Name of the desired column. - ILink ToDecimal(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Decimal. - /// - ILink ToDecimalOrNull(); - - /// - /// Indicates the results should be materialized as a nullable Decimal. - /// - /// Name of the desired column. - ILink ToDecimalOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Double. - /// - ILink ToDouble(); - - /// - /// Indicates the results should be materialized as a Double. - /// - /// Name of the desired column. - ILink ToDouble(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Double. - /// - ILink ToDoubleOrNull(); - - /// - /// Indicates the results should be materialized as a nullable Double. - /// - /// Name of the desired column. - ILink ToDoubleOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Guid. - /// - ILink ToGuid(); - - /// - /// Indicates the results should be materialized as a Guid. - /// - /// Name of the desired column. - ILink ToGuid(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Guid. - /// - ILink ToGuidOrNull(); - - /// - /// Indicates the results should be materialized as a nullable Guid. - /// - ILink ToGuidOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Int16. - /// - ILink ToInt16(); - - /// - /// Indicates the results should be materialized as a Int16. - /// - /// Name of the desired column. - ILink ToInt16(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Int16. - /// - ILink ToInt16OrNull(); - - /// - /// Indicates the results should be materialized as a nullable Int16. - /// - /// Name of the desired column. - ILink ToInt16OrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Int32. - /// - ILink ToInt32(); - - /// - /// Indicates the results should be materialized as a Int32. - /// - /// Name of the desired column. - ILink ToInt32(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Int32. - /// - ILink ToInt32OrNull(); - - /// - /// Indicates the results should be materialized as a nullable Int32. - /// - /// Name of the desired column. - ILink ToInt32OrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Int64. - /// - ILink ToInt64(); - - /// - /// Indicates the results should be materialized as a Int64. - /// - /// Name of the desired column. - ILink ToInt64(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Int64. - /// - ILink ToInt64OrNull(); - - /// - /// Indicates the results should be materialized as a nullable Int64. - /// - /// Name of the desired column. - ILink ToInt64OrNull(string columnName); - - /// - /// Indicates the results should be materialized as a Single. - /// - ILink ToSingle(); - - /// - /// Indicates the results should be materialized as a Single. - /// - /// Name of the desired column. - ILink ToSingle(string columnName); - - /// - /// Indicates the results should be materialized as a nullable Single. - /// - ILink ToSingleOrNull(); - - /// - /// Indicates the results should be materialized as a nullable Single. - /// - ILink ToSingleOrNull(string columnName); - - /// - /// Indicates the results should be materialized as a nullable string. - /// - /// - ILink ToString(); - - /// - /// Indicates the results should be materialized as a nullable string. - /// - /// - /// Name of the desired column. - ILink ToString(string columnName); - - /// - /// Indicates the results should be materialized as a TimeSpan. - /// - ILink ToTimeSpan(); - - /// - /// Indicates the results should be materialized as a TimeSpan. - /// - /// Name of the desired column. - ILink ToTimeSpan(string columnName); - - /// - /// Indicates the results should be materialized as a nullable TimeSpan. - /// - ILink ToTimeSpanOrNull(); - - /// - /// Indicates the results should be materialized as a nullable TimeSpan. - /// - /// Name of the desired column. - ILink ToTimeSpanOrNull(string columnName); - - /// - /// Materializes the result as an XElement. - /// - /// ILink<XElement>. - ILink ToXml(); - - /// - /// Materializes the result as an XElement. - /// - /// Name of the column. - /// ILink<XElement>. - ILink ToXml(string columnName); - } + /// Indicates the results should be materialized as a Boolean. + /// + ILink ToBoolean(); + + /// + /// Indicates the results should be materialized as a Boolean. + /// + /// Name of the desired column. + ILink ToBoolean(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Boolean. + /// + ILink ToBooleanOrNull(); + + /// + /// Indicates the results should be materialized as a nullable Boolean. + /// + /// Name of the desired column. + ILink ToBooleanOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a byte. + /// + ILink ToByte(); + + /// + /// Indicates the results should be materialized as a byte. + /// + /// Name of the desired column. + ILink ToByte(string columnName); + + /// + /// Indicates the results should be materialized as a byte array. + /// + ILink ToByteArray(); + + /// + /// Indicates the results should be materialized as a byte array. + /// + /// Name of the desired column. + ILink ToByteArray(string columnName); + + /// + /// Indicates the results should be materialized as a nullable byte. + /// + ILink ToByteOrNull(); + + /// + /// Indicates the results should be materialized as a nullable byte. + /// + /// Name of the desired column. + ILink ToByteOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a DateTime. + /// + ILink ToDateTime(); + + /// + /// Indicates the results should be materialized as a DateTime. + /// + /// Name of the desired column. + ILink ToDateTime(string columnName); + + /// + /// Indicates the results should be materialized as a DateTimeOffset. + /// + ILink ToDateTimeOffset(); + + /// + /// Indicates the results should be materialized as a DateTimeOffset. + /// + /// Name of the desired column. + ILink ToDateTimeOffset(string columnName); + + /// + /// Indicates the results should be materialized as a nullable DateTimeOffset. + /// + ILink ToDateTimeOffsetOrNull(); + + /// + /// Indicates the results should be materialized as a nullable DateTimeOffset. + /// + /// Name of the desired column. + ILink ToDateTimeOffsetOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a nullable DateTime. + /// + ILink ToDateTimeOrNull(); + + /// + /// Indicates the results should be materialized as a nullable DateTime. + /// + /// Name of the desired column. + ILink ToDateTimeOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Decimal. + /// + ILink ToDecimal(); + + /// + /// Indicates the results should be materialized as a Decimal. + /// + /// Name of the desired column. + ILink ToDecimal(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Decimal. + /// + ILink ToDecimalOrNull(); + + /// + /// Indicates the results should be materialized as a nullable Decimal. + /// + /// Name of the desired column. + ILink ToDecimalOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Double. + /// + ILink ToDouble(); + + /// + /// Indicates the results should be materialized as a Double. + /// + /// Name of the desired column. + ILink ToDouble(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Double. + /// + ILink ToDoubleOrNull(); + + /// + /// Indicates the results should be materialized as a nullable Double. + /// + /// Name of the desired column. + ILink ToDoubleOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Guid. + /// + ILink ToGuid(); + + /// + /// Indicates the results should be materialized as a Guid. + /// + /// Name of the desired column. + ILink ToGuid(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Guid. + /// + ILink ToGuidOrNull(); + + /// + /// Indicates the results should be materialized as a nullable Guid. + /// + ILink ToGuidOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Int16. + /// + ILink ToInt16(); + + /// + /// Indicates the results should be materialized as a Int16. + /// + /// Name of the desired column. + ILink ToInt16(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Int16. + /// + ILink ToInt16OrNull(); + + /// + /// Indicates the results should be materialized as a nullable Int16. + /// + /// Name of the desired column. + ILink ToInt16OrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Int32. + /// + ILink ToInt32(); + + /// + /// Indicates the results should be materialized as a Int32. + /// + /// Name of the desired column. + ILink ToInt32(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Int32. + /// + ILink ToInt32OrNull(); + + /// + /// Indicates the results should be materialized as a nullable Int32. + /// + /// Name of the desired column. + ILink ToInt32OrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Int64. + /// + ILink ToInt64(); + + /// + /// Indicates the results should be materialized as a Int64. + /// + /// Name of the desired column. + ILink ToInt64(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Int64. + /// + ILink ToInt64OrNull(); + + /// + /// Indicates the results should be materialized as a nullable Int64. + /// + /// Name of the desired column. + ILink ToInt64OrNull(string columnName); + + /// + /// Indicates the results should be materialized as a Single. + /// + ILink ToSingle(); + + /// + /// Indicates the results should be materialized as a Single. + /// + /// Name of the desired column. + ILink ToSingle(string columnName); + + /// + /// Indicates the results should be materialized as a nullable Single. + /// + ILink ToSingleOrNull(); + + /// + /// Indicates the results should be materialized as a nullable Single. + /// + ILink ToSingleOrNull(string columnName); + + /// + /// Indicates the results should be materialized as a nullable string. + /// + /// + ILink ToString(); + + /// + /// Indicates the results should be materialized as a nullable string. + /// + /// + /// Name of the desired column. + ILink ToString(string columnName); + + /// + /// Indicates the results should be materialized as a TimeSpan. + /// + ILink ToTimeSpan(); + + /// + /// Indicates the results should be materialized as a TimeSpan. + /// + /// Name of the desired column. + ILink ToTimeSpan(string columnName); + + /// + /// Indicates the results should be materialized as a nullable TimeSpan. + /// + ILink ToTimeSpanOrNull(); + + /// + /// Indicates the results should be materialized as a nullable TimeSpan. + /// + /// Name of the desired column. + ILink ToTimeSpanOrNull(string columnName); + + /// + /// Materializes the result as an XElement. + /// + /// ILink<XElement>. + ILink ToXml(); + + /// + /// Materializes the result as an XElement. + /// + /// Name of the column. + /// ILink<XElement>. + ILink ToXml(string columnName); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder.cs index e1111c966..c9443cacd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder.cs @@ -1,61 +1,60 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This allows the use of scalar and single row materializers against a command builder. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. +public interface ISingleRowDbCommandBuilder : IScalarDbCommandBuilder { /// - /// This allows the use of scalar and single row materializers against a command builder. - /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. - public interface ISingleRowDbCommandBuilder : IScalarDbCommandBuilder - { - /// - /// Indicates the results should be materialized as a Row. - /// - ILink ToDataRow(RowOptions rowOptions = RowOptions.None); - - /// - /// Indicates the results should be materialized as a Row. - /// - ILink ToDataRowOrNull(RowOptions rowOptions = RowOptions.None); - - /// - /// Materializes the result as a dynamic object - /// - /// The row options. - /// - ILink ToDynamicObject(RowOptions rowOptions = RowOptions.None); - - /// - /// Materializes the result as a dynamic object - /// - /// The row options. - /// - ILink ToDynamicObjectOrNull(RowOptions rowOptions = RowOptions.None); - - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) - where TObject : class; - - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TObject : class; - - /// - /// Indicates the results should be materialized as a Row. - /// - ILink ToRow(RowOptions rowOptions = RowOptions.None); - - /// - /// Indicates the results should be materialized as a Row. - /// - ILink ToRowOrNull(RowOptions rowOptions = RowOptions.None); - } + /// Indicates the results should be materialized as a Row. + /// + ILink ToDataRow(RowOptions rowOptions = RowOptions.None); + + /// + /// Indicates the results should be materialized as a Row. + /// + ILink ToDataRowOrNull(RowOptions rowOptions = RowOptions.None); + + /// + /// Materializes the result as a dynamic object + /// + /// The row options. + /// + ILink ToDynamicObject(RowOptions rowOptions = RowOptions.None); + + /// + /// Materializes the result as a dynamic object + /// + /// The row options. + /// + ILink ToDynamicObjectOrNull(RowOptions rowOptions = RowOptions.None); + + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) + where TObject : class; + + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TObject : class; + + /// + /// Indicates the results should be materialized as a Row. + /// + ILink ToRow(RowOptions rowOptions = RowOptions.None); + + /// + /// Indicates the results should be materialized as a Row. + /// + ILink ToRowOrNull(RowOptions rowOptions = RowOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder`1.cs index bf892ba7a..13b30eae2 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ISingleRowDbCommandBuilder`1.cs @@ -1,24 +1,23 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This allows the use of scalar and single row materializers against a command builder. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. +public interface ISingleRowDbCommandBuilder : ISingleRowDbCommandBuilder + where TObject : class { /// - /// This allows the use of scalar and single row materializers against a command builder. + /// Materializes the result as an instance of the indicated type /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. - public interface ISingleRowDbCommandBuilder : ISingleRowDbCommandBuilder - where TObject : class - { - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None); + /// The row options. + /// + IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None); - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder.cs index 6f1681b61..b907a63ac 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder.cs @@ -1,80 +1,79 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is a specialization of IMultipleRowDbCommandBuilder that includes support for sorting and limiting +/// +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. +/// +public interface ITableDbCommandBuilder : IMultipleRowDbCommandBuilder { /// - /// This is a specialization of IMultipleRowDbCommandBuilder that includes support for sorting and limiting + /// Returns the row count using a SELECT Count(*) style query. /// - /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. - /// - public interface ITableDbCommandBuilder : IMultipleRowDbCommandBuilder - { - /// - /// Returns the row count using a SELECT Count(*) style query. - /// - /// - ILink AsCount(); + /// + ILink AsCount(); - /// - /// Returns the row count for a given column. SELECT Count(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT(DISTINCT columnName). - /// - ILink AsCount(string columnName, bool distinct = false); + /// + /// Returns the row count for a given column. SELECT Count(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT(DISTINCT columnName). + /// + ILink AsCount(string columnName, bool distinct = false); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// - ITableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// + ITableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - ITableDbCommandBuilder WithFilter(string whereClause); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + ITableDbCommandBuilder WithFilter(string whereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - ITableDbCommandBuilder WithFilter(string whereClause, object? argumentValue); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + ITableDbCommandBuilder WithFilter(string whereClause, object? argumentValue); - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - ITableDbCommandBuilder WithLimits(int take, LimitOptions limitOptions = LimitOptions.Rows, int? seed = null); + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + ITableDbCommandBuilder WithLimits(int take, LimitOptions limitOptions = LimitOptions.Rows, int? seed = null); - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// The number of rows to take. - /// - /// Warning: row skipping using this method can be significantly slower than using a WHERE clause that uses an indexed column. - ITableDbCommandBuilder WithLimits(int skip, int take); + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// The number of rows to take. + /// + /// Warning: row skipping using this method can be significantly slower than using a WHERE clause that uses an indexed column. + ITableDbCommandBuilder WithLimits(int skip, int take); - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - ITableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions); + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + ITableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions); - /// - /// Adds sorting to the command builder - /// - /// The sort expressions. - /// - ITableDbCommandBuilder WithSorting(IEnumerable sortExpressions); - } + /// + /// Adds sorting to the command builder + /// + /// The sort expressions. + /// + ITableDbCommandBuilder WithSorting(IEnumerable sortExpressions); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder`1.cs index 5d8e64782..2e88aeb43 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ITableDbCommandBuilder`1.cs @@ -1,67 +1,66 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is a specialization of IMultipleRowDbCommandBuilder that includes support for sorting and limiting +/// +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. +/// +public interface ITableDbCommandBuilder : IMultipleRowDbCommandBuilder, ITableDbCommandBuilder + where TObject : class { /// - /// This is a specialization of IMultipleRowDbCommandBuilder that includes support for sorting and limiting + /// Adds (or replaces) the filter on this command builder. /// - /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new method will be added over time. - /// - public interface ITableDbCommandBuilder : IMultipleRowDbCommandBuilder, ITableDbCommandBuilder - where TObject : class - { - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// - new ITableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// The filter value. + /// The filter options. + /// + new ITableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - new ITableDbCommandBuilder WithFilter(string whereClause); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + new ITableDbCommandBuilder WithFilter(string whereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - new ITableDbCommandBuilder WithFilter(string whereClause, object? argumentValue); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + new ITableDbCommandBuilder WithFilter(string whereClause, object? argumentValue); - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - new ITableDbCommandBuilder WithLimits(int take, LimitOptions limitOptions = LimitOptions.Rows, int? seed = null); + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + new ITableDbCommandBuilder WithLimits(int take, LimitOptions limitOptions = LimitOptions.Rows, int? seed = null); - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// The number of rows to take. - /// - /// Warning: row skipping using this method can be significantly slower than using a WHERE clause that uses an indexed column. - new ITableDbCommandBuilder WithLimits(int skip, int take); + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// The number of rows to take. + /// + /// Warning: row skipping using this method can be significantly slower than using a WHERE clause that uses an indexed column. + new ITableDbCommandBuilder WithLimits(int skip, int take); - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - new ITableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions); + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + new ITableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions); - /// - /// Adds sorting to the command builder - /// - /// The sort expressions. - /// - new ITableDbCommandBuilder WithSorting(IEnumerable sortExpressions); - } + /// + /// Adds sorting to the command builder + /// + /// The sort expressions. + /// + new ITableDbCommandBuilder WithSorting(IEnumerable sortExpressions); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder.cs index e7726dec8..f5f92af69 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder.cs @@ -1,38 +1,37 @@ -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is a specialization of IMultipleRowDbCommandBuilder that includes support for sorting. It is only used for set-based update operations. +/// +/// +public interface IUpdateSetDbCommandBuilder { /// - /// This is a specialization of IMultipleRowDbCommandBuilder that includes support for sorting. It is only used for set-based update operations. + /// Applies this command to all rows. /// - /// - public interface IUpdateSetDbCommandBuilder - { - /// - /// Applies this command to all rows. - /// - /// - IMultipleRowDbCommandBuilder All(); + /// + IMultipleRowDbCommandBuilder All(); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// - IMultipleRowDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// + IMultipleRowDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - IMultipleRowDbCommandBuilder WithFilter(string whereClause); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + IMultipleRowDbCommandBuilder WithFilter(string whereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - IMultipleRowDbCommandBuilder WithFilter(string whereClause, object whereArgumentValue); - } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + IMultipleRowDbCommandBuilder WithFilter(string whereClause, object whereArgumentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder`2.cs index d1c1e738c..d66a02d12 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/IUpdateSetDbCommandBuilder`2.cs @@ -1,44 +1,43 @@ using System.Data.Common; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// Interface IUpdateSetCommandBuilder +/// +/// The type of the t command. +/// The type of the t parameter. +/// +public interface IUpdateSetDbCommandBuilder : IUpdateSetDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Interface IUpdateSetCommandBuilder + /// Applies this command to all rows. /// - /// The type of the t command. - /// The type of the t parameter. - /// - public interface IUpdateSetDbCommandBuilder : IUpdateSetDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Applies this command to all rows. - /// - /// - new MultipleRowDbCommandBuilder All(); + /// + new MultipleRowDbCommandBuilder All(); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// - new MultipleRowDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// + new MultipleRowDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - new MultipleRowDbCommandBuilder WithFilter(string whereClause); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + new MultipleRowDbCommandBuilder WithFilter(string whereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The where clause argument value. - /// - new MultipleRowDbCommandBuilder WithFilter(string whereClause, object? whereArgumentValue); - } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The where clause argument value. + /// + new MultipleRowDbCommandBuilder WithFilter(string whereClause, object? whereArgumentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`2.cs index 404c85222..13e5c22ad 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`2.cs @@ -5,1036 +5,1035 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for command builders that can potentially return multiple rows. +/// +/// The type of the t command type. +/// The type of the t parameter type. +public abstract class MultipleRowDbCommandBuilder : SingleRowDbCommandBuilder, IMultipleRowDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The data source. + protected MultipleRowDbCommandBuilder(ICommandDataSource dataSource) : base(dataSource) { } + /// - /// This is the base class for command builders that can potentially return multiple rows. - /// - /// The type of the t command type. - /// The type of the t parameter type. - public abstract class MultipleRowDbCommandBuilder : SingleRowDbCommandBuilder, IMultipleRowDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - { - /// Initializes a new instance of the class. - /// The data source. - protected MultipleRowDbCommandBuilder(ICommandDataSource dataSource) : base(dataSource) { } - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToBooleanList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new BooleanListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// The list options. - /// - public ILink> ToBooleanList(ListOptions listOptions = ListOptions.None) - { - return new BooleanListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// Name of the desired column. - /// The list options. - /// ILink<List<System.Nullable<System.Boolean>>>. - public ILink> ToBooleanOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new BooleanOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of booleans. - /// - /// The list options. - /// ILink<List<System.Nullable<System.Boolean>>>. - public ILink> ToBooleanOrNullList(ListOptions listOptions = ListOptions.None) - { - return new BooleanOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// The list options. - /// - public ILink> ToByteArrayList(ListOptions listOptions = ListOptions.None) - { - return new ByteArrayListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToByteArrayList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new ByteArrayListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Byte[]>>. - public ILink> ToByteArrayOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new ByteArrayOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of byte arrays. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Byte[]>>. - public ILink> ToByteArrayOrNullList(ListOptions listOptions = ListOptions.None) - { - return new ByteArrayOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of bytes. - /// - /// The list options. - /// - public ILink> ToByteList(ListOptions listOptions = ListOptions.None) - { - return new ByteListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of bytes. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToByteList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new ByteListMaterializer(this, columnName, listOptions); - } - - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The collection options. - /// - public IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class - { - return ToCollection>(collectionOptions); - } - - /// - /// Materializes the result as a list of objects. - /// - /// The type of the model. - /// The type of the collection. - /// The collection options. - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public IConstructibleMaterializer ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class - where TCollection : ICollection, new() - { - return new CollectionMaterializer(this, collectionOptions); - } - - /// - /// Indicates the results should be materialized as a DataSet. - /// - public ILink ToDataTable() - { - return new DataTableMaterializer(this); - } - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToDateTimeList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DateTimeListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// The list options. - /// - public ILink> ToDateTimeList(ListOptions listOptions = ListOptions.None) - { - return new DateTimeListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToDateTimeOffsetList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DateTimeOffsetListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// The list options. - /// - public ILink> ToDateTimeOffsetList(ListOptions listOptions = ListOptions.None) - { - return new DateTimeOffsetListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTimeOffset>>>. - public ILink> ToDateTimeOffsetOrNullList(ListOptions listOptions = ListOptions.None) - { - return new DateTimeOffsetOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTimeOffset. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTimeOffset>>>. - public ILink> ToDateTimeOffsetOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DateTimeOffsetOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of DateTimeOffset. - /// - /// The list options. - /// ILink<HashSet<DateTimeOffset>>. - public ILink> ToDateTimeOffsetSet(ListOptions listOptions = ListOptions.None) - { - return new DateTimeOffsetSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of DateTimeOffset. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<DateTimeOffset>>. - public ILink> ToDateTimeOffsetSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DateTimeOffsetSetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTime>>>. - public ILink> ToDateTimeOrNullList(ListOptions listOptions = ListOptions.None) - { - return new DateTimeOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of DateTime. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTime>>>. - public ILink> ToDateTimeOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DateTimeOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of DateTime. - /// - /// The list options. - /// ILink<HashSet<DateTime>>. - public ILink> ToDateTimeSet(ListOptions listOptions = ListOptions.None) - { - return new DateTimeSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of DateTime. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<DateTime>>. - public ILink> ToDateTimeSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DateTimeSetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToDecimalList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DecimalListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - public ILink> ToDecimalList(ListOptions listOptions = ListOptions.None) - { - return new DecimalListMaterializer(this, null, listOptions); - } - - /// - /// Converts to decimalornulllist. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Decimal>>>. - public ILink> ToDecimalOrNullList(ListOptions listOptions = ListOptions.None) - { - return new DecimalOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Decimal>>>. - public ILink> ToDecimalOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DecimalOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// The list options. - /// ILink<HashSet<System.Decimal>>. - public ILink> ToDecimalSet(ListOptions listOptions = ListOptions.None) - { - return new DecimalSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.Decimal>>. - public ILink> ToDecimalSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DecimalSetMaterializer(this, columnName, listOptions); - } - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key column. - /// The dictionary options. - /// - public IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - { - return ToDictionary>(keyColumn, dictionaryOptions); - } - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The type of dictionary. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public IConstructibleMaterializer ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - where TDictionary : IDictionary, new() - { - return new DictionaryMaterializer(this, keyColumn, dictionaryOptions); - } - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key function. - /// The dictionary options. - /// - public IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - { - return ToDictionary>(keyFunction, dictionaryOptions); - } - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The type of dictionary. - /// The key function. - /// The dictionary options. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public IConstructibleMaterializer ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - where TDictionary : IDictionary, new() - { - return new DictionaryMaterializer(this, keyFunction, dictionaryOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToDoubleList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DoubleListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - public ILink> ToDoubleList(ListOptions listOptions = ListOptions.None) - { - return new DoubleListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Double>>>. - public ILink> ToDoubleOrNullList(ListOptions listOptions = ListOptions.None) - { - return new DoubleOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Double>>>. - public ILink> ToDoubleOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DoubleOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// The list options. - /// ILink<HashSet<System.Double>>. - public ILink> ToDoubleSet(ListOptions listOptions = ListOptions.None) - { - return new DoubleSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.Double>>. - public ILink> ToDoubleSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new DoubleSetMaterializer(this, columnName, listOptions); - } - - /// - /// Materializes the result as a list of dynamically typed objects. - /// - /// - public ILink> ToDynamicCollection() - { - return new DynamicCollectionMaterializer(this); - } - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToGuidList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new GuidListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// The list options. - /// - public ILink> ToGuidList(ListOptions listOptions = ListOptions.None) - { - return new GuidListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Guid>>>. - public ILink> ToGuidOrNullList(ListOptions listOptions = ListOptions.None) - { - return new GuidOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of Guids. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Guid>>>. - public ILink> ToGuidOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new GuidOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of Guids. - /// - /// The list options. - /// ILink<HashSet<Guid>>. - public ILink> ToGuidSet(ListOptions listOptions = ListOptions.None) - { - return new GuidSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of Guids. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<Guid>>. - public ILink> ToGuidSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new GuidSetMaterializer(this, columnName, listOptions); - } - - /// - /// Materializes the result as an immutable array of objects. - /// - /// The type of the model. - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. - public IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) - where TObject : class - { - return new ImmutableArrayMaterializer(this, collectionOptions); - } - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key function. - /// The dictionary options. - /// - public IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - { - return new ImmutableDictionaryMaterializer(this, keyFunction, dictionaryOptions); - } - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The type of the model. - /// The key column. - /// The dictionary options. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - where TObject : class - { - return new ImmutableDictionaryMaterializer(this, keyColumn, dictionaryOptions); - } - - /// - /// Materializes the result as an immutable list of objects. - /// - /// The type of the model. - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. - public IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) + /// Indicates the results should be materialized as a list of booleans. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToBooleanList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new BooleanListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of booleans. + /// + /// The list options. + /// + public ILink> ToBooleanList(ListOptions listOptions = ListOptions.None) + { + return new BooleanListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of booleans. + /// + /// Name of the desired column. + /// The list options. + /// ILink<List<System.Nullable<System.Boolean>>>. + public ILink> ToBooleanOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new BooleanOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of booleans. + /// + /// The list options. + /// ILink<List<System.Nullable<System.Boolean>>>. + public ILink> ToBooleanOrNullList(ListOptions listOptions = ListOptions.None) + { + return new BooleanOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// The list options. + /// + public ILink> ToByteArrayList(ListOptions listOptions = ListOptions.None) + { + return new ByteArrayListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToByteArrayList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new ByteArrayListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Byte[]>>. + public ILink> ToByteArrayOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new ByteArrayOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of byte arrays. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Byte[]>>. + public ILink> ToByteArrayOrNullList(ListOptions listOptions = ListOptions.None) + { + return new ByteArrayOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of bytes. + /// + /// The list options. + /// + public ILink> ToByteList(ListOptions listOptions = ListOptions.None) + { + return new ByteListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of bytes. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToByteList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new ByteListMaterializer(this, columnName, listOptions); + } + + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The collection options. + /// + public IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class + { + return ToCollection>(collectionOptions); + } + + /// + /// Materializes the result as a list of objects. + /// + /// The type of the model. + /// The type of the collection. + /// The collection options. + /// + /// + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public IConstructibleMaterializer ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class + where TCollection : ICollection, new() + { + return new CollectionMaterializer(this, collectionOptions); + } + + /// + /// Indicates the results should be materialized as a DataSet. + /// + public ILink ToDataTable() + { + return new DataTableMaterializer(this); + } + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToDateTimeList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DateTimeListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// The list options. + /// + public ILink> ToDateTimeList(ListOptions listOptions = ListOptions.None) + { + return new DateTimeListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToDateTimeOffsetList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DateTimeOffsetListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// The list options. + /// + public ILink> ToDateTimeOffsetList(ListOptions listOptions = ListOptions.None) + { + return new DateTimeOffsetListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTimeOffset>>>. + public ILink> ToDateTimeOffsetOrNullList(ListOptions listOptions = ListOptions.None) + { + return new DateTimeOffsetOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTimeOffset. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTimeOffset>>>. + public ILink> ToDateTimeOffsetOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DateTimeOffsetOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of DateTimeOffset. + /// + /// The list options. + /// ILink<HashSet<DateTimeOffset>>. + public ILink> ToDateTimeOffsetSet(ListOptions listOptions = ListOptions.None) + { + return new DateTimeOffsetSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of DateTimeOffset. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<DateTimeOffset>>. + public ILink> ToDateTimeOffsetSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DateTimeOffsetSetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTime>>>. + public ILink> ToDateTimeOrNullList(ListOptions listOptions = ListOptions.None) + { + return new DateTimeOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of DateTime. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.DateTime>>>. + public ILink> ToDateTimeOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DateTimeOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of DateTime. + /// + /// The list options. + /// ILink<HashSet<DateTime>>. + public ILink> ToDateTimeSet(ListOptions listOptions = ListOptions.None) + { + return new DateTimeSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of DateTime. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<DateTime>>. + public ILink> ToDateTimeSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DateTimeSetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToDecimalList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DecimalListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + public ILink> ToDecimalList(ListOptions listOptions = ListOptions.None) + { + return new DecimalListMaterializer(this, null, listOptions); + } + + /// + /// Converts to decimalornulllist. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Decimal>>>. + public ILink> ToDecimalOrNullList(ListOptions listOptions = ListOptions.None) + { + return new DecimalOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Decimal>>>. + public ILink> ToDecimalOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DecimalOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// The list options. + /// ILink<HashSet<System.Decimal>>. + public ILink> ToDecimalSet(ListOptions listOptions = ListOptions.None) + { + return new DecimalSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.Decimal>>. + public ILink> ToDecimalSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DecimalSetMaterializer(this, columnName, listOptions); + } + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key column. + /// The dictionary options. + /// + public IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + { + return ToDictionary>(keyColumn, dictionaryOptions); + } + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The type of dictionary. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public IConstructibleMaterializer ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + where TDictionary : IDictionary, new() + { + return new DictionaryMaterializer(this, keyColumn, dictionaryOptions); + } + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key function. + /// The dictionary options. + /// + public IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + { + return ToDictionary>(keyFunction, dictionaryOptions); + } + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The type of dictionary. + /// The key function. + /// The dictionary options. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public IConstructibleMaterializer ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + where TDictionary : IDictionary, new() + { + return new DictionaryMaterializer(this, keyFunction, dictionaryOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToDoubleList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DoubleListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + public ILink> ToDoubleList(ListOptions listOptions = ListOptions.None) + { + return new DoubleListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Double>>>. + public ILink> ToDoubleOrNullList(ListOptions listOptions = ListOptions.None) + { + return new DoubleOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Double>>>. + public ILink> ToDoubleOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DoubleOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// The list options. + /// ILink<HashSet<System.Double>>. + public ILink> ToDoubleSet(ListOptions listOptions = ListOptions.None) + { + return new DoubleSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.Double>>. + public ILink> ToDoubleSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new DoubleSetMaterializer(this, columnName, listOptions); + } + + /// + /// Materializes the result as a list of dynamically typed objects. + /// + /// + public ILink> ToDynamicCollection() + { + return new DynamicCollectionMaterializer(this); + } + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToGuidList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new GuidListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// The list options. + /// + public ILink> ToGuidList(ListOptions listOptions = ListOptions.None) + { + return new GuidListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Guid>>>. + public ILink> ToGuidOrNullList(ListOptions listOptions = ListOptions.None) + { + return new GuidOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of Guids. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Guid>>>. + public ILink> ToGuidOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new GuidOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of Guids. + /// + /// The list options. + /// ILink<HashSet<Guid>>. + public ILink> ToGuidSet(ListOptions listOptions = ListOptions.None) + { + return new GuidSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of Guids. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<Guid>>. + public ILink> ToGuidSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new GuidSetMaterializer(this, columnName, listOptions); + } + + /// + /// Materializes the result as an immutable array of objects. + /// + /// The type of the model. + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. + public IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) +where TObject : class + { + return new ImmutableArrayMaterializer(this, collectionOptions); + } + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key function. + /// The dictionary options. + /// + public IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull where TObject : class - { - return new ImmutableListMaterializer(this, collectionOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToInt16List(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int16ListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - public ILink> ToInt16List(ListOptions listOptions = ListOptions.None) - { - return new Int16ListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int16>>>. - public ILink> ToInt16OrNullList(ListOptions listOptions = ListOptions.None) - { - return new Int16OrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int16>>>. - public ILink> ToInt16OrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int16OrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// The list options. - /// ILink<HashSet<System.Int16>>. - public ILink> ToInt16Set(ListOptions listOptions = ListOptions.None) - { - return new Int16SetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.Int16>>. - public ILink> ToInt16Set(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int16SetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToInt32List(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int32ListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - public ILink> ToInt32List(ListOptions listOptions = ListOptions.None) - { - return new Int32ListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int32>>>. - public ILink> ToInt32OrNullList(ListOptions listOptions = ListOptions.None) - { - return new Int32OrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int32>>>. - public ILink> ToInt32OrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int32OrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// The list options. - /// ILink<HashSet<System.Int32>>. - public ILink> ToInt32Set(ListOptions listOptions = ListOptions.None) - { - return new Int32SetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.Int32>>. - public ILink> ToInt32Set(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int32SetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToInt64List(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int64ListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// - public ILink> ToInt64List(ListOptions listOptions = ListOptions.None) - { - return new Int64ListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int64>>>. - public ILink> ToInt64OrNullList(ListOptions listOptions = ListOptions.None) - { - return new Int64OrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of integers. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int64>>>. - public ILink> ToInt64OrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int64OrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// The list options. - /// ILink<HashSet<System.Int64>>. - public ILink> ToInt64Set(ListOptions listOptions = ListOptions.None) - { - return new Int64SetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of integers. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.Int64>>. - public ILink> ToInt64Set(string columnName, ListOptions listOptions = ListOptions.None) - { - return new Int64SetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToSingleList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new SingleListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// - public ILink> ToSingleList(ListOptions listOptions = ListOptions.None) - { - return new SingleListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Single>>>. - public ILink> ToSingleOrNullList(ListOptions listOptions = ListOptions.None) - { - return new SingleOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of numbers. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Single>>>. - public ILink> ToSingleOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new SingleOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// The list options. - /// ILink<HashSet<System.Single>>. - public ILink> ToSingleSet(ListOptions listOptions = ListOptions.None) - { - return new SingleSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of numbers. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.Single>>. - public ILink> ToSingleSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new SingleSetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToStringList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new StringListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// The list options. - /// - public ILink> ToStringList(ListOptions listOptions = ListOptions.None) - { - return new StringListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.String>>. - public ILink> ToStringOrNullList(ListOptions listOptions = ListOptions.None) - { - return new StringOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of strings. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.String>>. - public ILink> ToStringOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new StringOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of strings. - /// - /// The list options. - /// ILink<HashSet<System.String>>. - public ILink> ToStringSet(ListOptions listOptions = ListOptions.None) - { - return new StringSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of strings. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<System.String>>. - public ILink> ToStringSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new StringSetMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a Table. - /// - public ILink
ToTable() - { - return new TableMaterializer(this); - } - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// Name of the desired column. - /// The list options. - /// - public ILink> ToTimeSpanList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new TimeSpanListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// The list options. - /// - public ILink> ToTimeSpanList(ListOptions listOptions = ListOptions.None) - { - return new TimeSpanListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.TimeSpan>>>. - public ILink> ToTimeSpanOrNullList(ListOptions listOptions = ListOptions.None) - { - return new TimeSpanOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a list of TimeSpan. - /// - /// Name of the desired column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.TimeSpan>>>. - public ILink> ToTimeSpanOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new TimeSpanOrNullListMaterializer(this, columnName, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of TimeSpan. - /// - /// The list options. - /// ILink<HashSet<TimeSpan>>. - public ILink> ToTimeSpanSet(ListOptions listOptions = ListOptions.None) - { - return new TimeSpanSetMaterializer(this, null, listOptions); - } - - /// - /// Indicates the results should be materialized as a set of TimeSpan. - /// - /// Name of the desired column. - /// The list options. - /// ILink<HashSet<TimeSpan>>. - public ILink> ToTimeSpanSet(string columnName, ListOptions listOptions = ListOptions.None) - { - return new TimeSpanSetMaterializer(this, columnName, listOptions); - } - - /// - /// Materializes the result as a list of XElement. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - public ILink> ToXmlList(ListOptions listOptions = ListOptions.None) - { - return new XElementListMaterializer(this, null, listOptions); - } - - /// - /// Materializes the result as a list of XElement. - /// - /// Name of the column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - public ILink> ToXmlList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new XElementListMaterializer(this, columnName, listOptions); - } - - /// - /// Materializes the result as a list of XElement. - /// - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - public ILink> ToXmlOrNullList(ListOptions listOptions = ListOptions.None) - { - return new XElementOrNullListMaterializer(this, null, listOptions); - } - - /// - /// Materializes the result as a list of XElement. - /// - /// Name of the column. - /// The list options. - /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. - public ILink> ToXmlOrNullList(string columnName, ListOptions listOptions = ListOptions.None) - { - return new XElementOrNullListMaterializer(this, columnName, listOptions); - } + { + return new ImmutableDictionaryMaterializer(this, keyFunction, dictionaryOptions); + } + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The type of the model. + /// The key column. + /// The dictionary options. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + where TObject : class + { + return new ImmutableDictionaryMaterializer(this, keyColumn, dictionaryOptions); + } + + /// + /// Materializes the result as an immutable list of objects. + /// + /// The type of the model. + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. + public IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) + where TObject : class + { + return new ImmutableListMaterializer(this, collectionOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToInt16List(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int16ListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + public ILink> ToInt16List(ListOptions listOptions = ListOptions.None) + { + return new Int16ListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int16>>>. + public ILink> ToInt16OrNullList(ListOptions listOptions = ListOptions.None) + { + return new Int16OrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int16>>>. + public ILink> ToInt16OrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int16OrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// The list options. + /// ILink<HashSet<System.Int16>>. + public ILink> ToInt16Set(ListOptions listOptions = ListOptions.None) + { + return new Int16SetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.Int16>>. + public ILink> ToInt16Set(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int16SetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToInt32List(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int32ListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + public ILink> ToInt32List(ListOptions listOptions = ListOptions.None) + { + return new Int32ListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int32>>>. + public ILink> ToInt32OrNullList(ListOptions listOptions = ListOptions.None) + { + return new Int32OrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int32>>>. + public ILink> ToInt32OrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int32OrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// The list options. + /// ILink<HashSet<System.Int32>>. + public ILink> ToInt32Set(ListOptions listOptions = ListOptions.None) + { + return new Int32SetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.Int32>>. + public ILink> ToInt32Set(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int32SetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToInt64List(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int64ListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// + public ILink> ToInt64List(ListOptions listOptions = ListOptions.None) + { + return new Int64ListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int64>>>. + public ILink> ToInt64OrNullList(ListOptions listOptions = ListOptions.None) + { + return new Int64OrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of integers. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Int64>>>. + public ILink> ToInt64OrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int64OrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// The list options. + /// ILink<HashSet<System.Int64>>. + public ILink> ToInt64Set(ListOptions listOptions = ListOptions.None) + { + return new Int64SetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of integers. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.Int64>>. + public ILink> ToInt64Set(string columnName, ListOptions listOptions = ListOptions.None) + { + return new Int64SetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToSingleList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new SingleListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// + public ILink> ToSingleList(ListOptions listOptions = ListOptions.None) + { + return new SingleListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Single>>>. + public ILink> ToSingleOrNullList(ListOptions listOptions = ListOptions.None) + { + return new SingleOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of numbers. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.Single>>>. + public ILink> ToSingleOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new SingleOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// The list options. + /// ILink<HashSet<System.Single>>. + public ILink> ToSingleSet(ListOptions listOptions = ListOptions.None) + { + return new SingleSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of numbers. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.Single>>. + public ILink> ToSingleSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new SingleSetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToStringList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new StringListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// The list options. + /// + public ILink> ToStringList(ListOptions listOptions = ListOptions.None) + { + return new StringListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.String>>. + public ILink> ToStringOrNullList(ListOptions listOptions = ListOptions.None) + { + return new StringOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of strings. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.String>>. + public ILink> ToStringOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new StringOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of strings. + /// + /// The list options. + /// ILink<HashSet<System.String>>. + public ILink> ToStringSet(ListOptions listOptions = ListOptions.None) + { + return new StringSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of strings. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<System.String>>. + public ILink> ToStringSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new StringSetMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a Table. + /// + public ILink
ToTable() + { + return new TableMaterializer(this); + } + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// Name of the desired column. + /// The list options. + /// + public ILink> ToTimeSpanList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new TimeSpanListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// The list options. + /// + public ILink> ToTimeSpanList(ListOptions listOptions = ListOptions.None) + { + return new TimeSpanListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.TimeSpan>>>. + public ILink> ToTimeSpanOrNullList(ListOptions listOptions = ListOptions.None) + { + return new TimeSpanOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a list of TimeSpan. + /// + /// Name of the desired column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<System.Nullable<System.TimeSpan>>>. + public ILink> ToTimeSpanOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new TimeSpanOrNullListMaterializer(this, columnName, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of TimeSpan. + /// + /// The list options. + /// ILink<HashSet<TimeSpan>>. + public ILink> ToTimeSpanSet(ListOptions listOptions = ListOptions.None) + { + return new TimeSpanSetMaterializer(this, null, listOptions); + } + + /// + /// Indicates the results should be materialized as a set of TimeSpan. + /// + /// Name of the desired column. + /// The list options. + /// ILink<HashSet<TimeSpan>>. + public ILink> ToTimeSpanSet(string columnName, ListOptions listOptions = ListOptions.None) + { + return new TimeSpanSetMaterializer(this, columnName, listOptions); + } + + /// + /// Materializes the result as a list of XElement. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + public ILink> ToXmlList(ListOptions listOptions = ListOptions.None) + { + return new XElementListMaterializer(this, null, listOptions); + } + + /// + /// Materializes the result as a list of XElement. + /// + /// Name of the column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + public ILink> ToXmlList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new XElementListMaterializer(this, columnName, listOptions); + } + + /// + /// Materializes the result as a list of XElement. + /// + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + public ILink> ToXmlOrNullList(ListOptions listOptions = ListOptions.None) + { + return new XElementOrNullListMaterializer(this, null, listOptions); + } + + /// + /// Materializes the result as a list of XElement. + /// + /// Name of the column. + /// The list options. + /// Tortuga.Chain.ILink<System.Collections.Generic.List<XDocument>>. + public ILink> ToXmlOrNullList(string columnName, ListOptions listOptions = ListOptions.None) + { + return new XElementOrNullListMaterializer(this, columnName, listOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`3.cs index 4789496cd..71d250b41 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleRowDbCommandBuilder`3.cs @@ -4,166 +4,165 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// Class MultipleRowDbCommandBuilder is an adapter used to add a return type for subclasses of MultipleRowDbCommandBuilder{TCommand, TParameter}. +/// +/// The type of the t command. +/// The type of the t parameter. +/// The type of the t object. +public class MultipleRowDbCommandBuilder : MultipleRowDbCommandBuilder, IMultipleRowDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class { + readonly MultipleRowDbCommandBuilder m_CommandBuilder; + + /// + /// Initializes a new instance of the class. + /// + /// The command builder. + /// commandBuilder + public MultipleRowDbCommandBuilder(MultipleRowDbCommandBuilder commandBuilder) + : base(commandBuilder?.DataSource ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null.")) + { + m_CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + return m_CommandBuilder.Prepare(materializer); + } + + /// + /// Materializes the result as a list of objects. + /// + /// The collection options. + /// IConstructibleMaterializer<List<TObject>>. + public IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + { + return m_CommandBuilder.ToCollection(collectionOptions); + } + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The key column. + /// The dictionary options. + /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. + /// + public IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + { + return m_CommandBuilder.ToDictionary(keyColumn, dictionaryOptions); + } + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The key function. + /// The dictionary options. + /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. + + public IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + { + return m_CommandBuilder.ToDictionary(keyFunction, dictionaryOptions); + } + + /// + /// Materializes the result as an immutable array of objects. + /// + /// The collection options. + /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. + public IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) + { + return m_CommandBuilder.ToImmutableArray(collectionOptions); + } + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The key function. + /// The dictionary options. + /// IConstructibleMaterializer<ImmutableDictionary<TKey, TObject>>. + + public IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + { + return m_CommandBuilder.ToImmutableDictionary(keyFunction, dictionaryOptions); + } + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The key column. + /// The dictionary options. + /// IConstructibleMaterializer<ImmutableDictionary<TKey, TObject>>. + + public IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + { + return m_CommandBuilder.ToImmutableDictionary(keyColumn, dictionaryOptions); + } + + /// + /// Materializes the result as an immutable list of objects. + /// + /// The collection options. + /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. + public IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) + { + return m_CommandBuilder.ToImmutableList(collectionOptions); + } + + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// IConstructibleMaterializer<TObject>. + public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) + { + return m_CommandBuilder.ToObject(rowOptions); + } + + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// IConstructibleMaterializer<TObject>. + public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + { + return m_CommandBuilder.ToObjectOrNull(rowOptions); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// If the column name was not found, this will return null + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_CommandBuilder.TryGetColumn(columnName); + } + /// - /// Class MultipleRowDbCommandBuilder is an adapter used to add a return type for subclasses of MultipleRowDbCommandBuilder{TCommand, TParameter}. + /// Returns a list of columns known to be non-nullable. /// - /// The type of the t command. - /// The type of the t parameter. - /// The type of the t object. - public class MultipleRowDbCommandBuilder : MultipleRowDbCommandBuilder, IMultipleRowDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// This is used by materializers to skip IsNull checks. + public override IReadOnlyList TryGetNonNullableColumns() { - readonly MultipleRowDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// commandBuilder - public MultipleRowDbCommandBuilder(MultipleRowDbCommandBuilder commandBuilder) - : base(commandBuilder?.DataSource ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null.")) - { - m_CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - return m_CommandBuilder.Prepare(materializer); - } - - /// - /// Materializes the result as a list of objects. - /// - /// The collection options. - /// IConstructibleMaterializer<List<TObject>>. - public IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - { - return m_CommandBuilder.ToCollection(collectionOptions); - } - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The key column. - /// The dictionary options. - /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. - /// - public IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - { - return m_CommandBuilder.ToDictionary(keyColumn, dictionaryOptions); - } - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The key function. - /// The dictionary options. - /// IConstructibleMaterializer<Dictionary<TKey, TObject>>. - - public IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - { - return m_CommandBuilder.ToDictionary(keyFunction, dictionaryOptions); - } - - /// - /// Materializes the result as an immutable array of objects. - /// - /// The collection options. - /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. - public IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) - { - return m_CommandBuilder.ToImmutableArray(collectionOptions); - } - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The key function. - /// The dictionary options. - /// IConstructibleMaterializer<ImmutableDictionary<TKey, TObject>>. - - public IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - { - return m_CommandBuilder.ToImmutableDictionary(keyFunction, dictionaryOptions); - } - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The key column. - /// The dictionary options. - /// IConstructibleMaterializer<ImmutableDictionary<TKey, TObject>>. - - public IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - { - return m_CommandBuilder.ToImmutableDictionary(keyColumn, dictionaryOptions); - } - - /// - /// Materializes the result as an immutable list of objects. - /// - /// The collection options. - /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. - public IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) - { - return m_CommandBuilder.ToImmutableList(collectionOptions); - } - - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// IConstructibleMaterializer<TObject>. - public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) - { - return m_CommandBuilder.ToObject(rowOptions); - } - - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// IConstructibleMaterializer<TObject>. - public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - { - return m_CommandBuilder.ToObjectOrNull(rowOptions); - } - - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// If the column name was not found, this will return null - public override ColumnMetadata? TryGetColumn(string columnName) - { - return m_CommandBuilder.TryGetColumn(columnName); - } - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// This is used by materializers to skip IsNull checks. - public override IReadOnlyList TryGetNonNullableColumns() - { - return m_CommandBuilder.TryGetNonNullableColumns(); - } + return m_CommandBuilder.TryGetNonNullableColumns(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleTableDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleTableDbCommandBuilder`2.cs index 36cd2139a..22c97e214 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleTableDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/MultipleTableDbCommandBuilder`2.cs @@ -3,97 +3,96 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for command builders that can potentially return multiple result sets. +/// +/// The type of the t command type. +/// The type of the t parameter type. +[SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] +public abstract class MultipleTableDbCommandBuilder : MultipleRowDbCommandBuilder, IMultipleTableDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The data source. + protected MultipleTableDbCommandBuilder(ICommandDataSource dataSource) + : base(dataSource) + { } + /// - /// This is the base class for command builders that can potentially return multiple result sets. + /// To the collection set. /// - /// The type of the t command type. - /// The type of the t parameter type. - [SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] - public abstract class MultipleTableDbCommandBuilder : MultipleRowDbCommandBuilder, IMultipleTableDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// + public ILink, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() { - /// Initializes a new instance of the class. - /// The data source. - protected MultipleTableDbCommandBuilder(ICommandDataSource dataSource) - : base(dataSource) - { } - - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// - public ILink, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - { - return new CollectionSetMaterializer(this); - } + return new CollectionSetMaterializer(this); + } - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// The type of the 3rd collection. - /// - public ILink, List, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - { - return new CollectionSetMaterializer(this); - } + /// + /// To the collection set. + /// + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// The type of the 3rd collection. + /// + public ILink, List, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + { + return new CollectionSetMaterializer(this); + } - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// The type of the 3rd collection. - /// The type of the 4th collection. - /// - public ILink, List, List, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - where T4 : class, new() - { - return new CollectionSetMaterializer(this); - } + /// + /// To the collection set. + /// + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// The type of the 3rd collection. + /// The type of the 4th collection. + /// + public ILink, List, List, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + where T4 : class, new() + { + return new CollectionSetMaterializer(this); + } - /// - /// To the collection set. - /// - /// The type of the 1st collection. - /// The type of the 2nd collection. - /// The type of the 3rd collection. - /// The type of the 4th collection. - /// The type of the 5th collection. - /// - public ILink, List, List, List, List>> ToCollectionSet() - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - where T4 : class, new() - where T5 : class, new() - { - return new CollectionSetMaterializer(this); - } + /// + /// To the collection set. + /// + /// The type of the 1st collection. + /// The type of the 2nd collection. + /// The type of the 3rd collection. + /// The type of the 4th collection. + /// The type of the 5th collection. + /// + public ILink, List, List, List, List>> ToCollectionSet() + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + where T4 : class, new() + where T5 : class, new() + { + return new CollectionSetMaterializer(this); + } - /// - /// Indicates the results should be materialized as a DataSet. - /// - /// The table names. - public ILink ToDataSet(params string[] tableNames) { return new DataSetMaterializer(this, tableNames); } + /// + /// Indicates the results should be materialized as a DataSet. + /// + /// The table names. + public ILink ToDataSet(params string[] tableNames) { return new DataSetMaterializer(this, tableNames); } - /// - /// Indicates the results should be materialized as a set of tables. - /// - public ILink ToTableSet(params string[] tableNames) { return new TableSetMaterializer(this, tableNames); } - } + /// + /// Indicates the results should be materialized as a set of tables. + /// + public ILink ToTableSet(params string[] tableNames) { return new TableSetMaterializer(this, tableNames); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ObjectDbCommandBuilder`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ObjectDbCommandBuilder`3.cs index 3b009cc60..240c40765 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ObjectDbCommandBuilder`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ObjectDbCommandBuilder`3.cs @@ -4,117 +4,116 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This represents command builders that operate on single object parameters: Insert, Update, Upsert, Delete +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the argument. +public abstract class ObjectDbCommandBuilder : SingleRowDbCommandBuilder, IObjectDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter + where TArgument : class { /// - /// This represents command builders that operate on single object parameters: Insert, Update, Upsert, Delete + /// Initializes a new instance of the class. /// - /// The type of the command. - /// The type of the parameter. - /// The type of the argument. - public abstract class ObjectDbCommandBuilder : SingleRowDbCommandBuilder, IObjectDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - where TArgument : class + /// The data source. + /// The argument value. + protected ObjectDbCommandBuilder(ICommandDataSource dataSource, TArgument argumentValue) : base(dataSource) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The argument value. - protected ObjectDbCommandBuilder(ICommandDataSource dataSource, TArgument argumentValue) : base(dataSource) - { - ArgumentValue = argumentValue; - } - - /// - /// Gets the argument value passed to the command builder. - /// - /// The argument value. - public TArgument ArgumentValue { get; } + ArgumentValue = argumentValue; + } - /// - /// Gets the set of key column(s) to use instead of the primary key(s). - /// - protected ImmutableHashSet KeyColumns { get; private set; } = ImmutableHashSet.Empty; + /// + /// Gets the argument value passed to the command builder. + /// + /// The argument value. + public TArgument ArgumentValue { get; } - /// - /// Materializes the result as a new instance of the same type as the argumentValue - /// - /// The row options. - /// - /// To update the argumentValue itself, use WithRefresh() instead. - public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) => new ObjectOrNullMaterializer(this, rowOptions); + /// + /// Gets the set of key column(s) to use instead of the primary key(s). + /// + protected ImmutableHashSet KeyColumns { get; private set; } = ImmutableHashSet.Empty; - /// - /// Materializes the result as a new instance of the same type as the argumentValue - /// - /// The row options. - /// - /// To update the argumentValue itself, use WithRefresh() instead. - public ILink ToObject(RowOptions rowOptions = RowOptions.None) - { - return new ObjectMaterializer(this, rowOptions); - } + /// + /// Materializes the result as a new instance of the same type as the argumentValue + /// + /// The row options. + /// + /// To update the argumentValue itself, use WithRefresh() instead. + public ILink ToObject(RowOptions rowOptions = RowOptions.None) + { + return new ObjectMaterializer(this, rowOptions); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override sealed ColumnMetadata? TryGetColumn(string columnName) - { - return OnGetTable().Columns.TryGetColumn(columnName); - } + /// + /// Materializes the result as a new instance of the same type as the argumentValue + /// + /// The row options. + /// + /// To update the argumentValue itself, use WithRefresh() instead. + public ILink ToObjectOrNull(RowOptions rowOptions = RowOptions.None) => new ObjectOrNullMaterializer(this, rowOptions); - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override sealed IReadOnlyList TryGetNonNullableColumns() => OnGetTable().NonNullableColumns; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override sealed ColumnMetadata? TryGetColumn(string columnName) + { + return OnGetTable().Columns.TryGetColumn(columnName); + } - /// - /// Uses an explicitly specified set of key column(s). This overrides the UseKeyAttribute option. - /// - /// The column names that form a unique key. - /// - public ObjectDbCommandBuilder WithKeys(params string[] columnNames) - { - var table = OnGetTable(); + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override sealed IReadOnlyList TryGetNonNullableColumns() => OnGetTable().NonNullableColumns; - //normalize the column names. - KeyColumns = columnNames.Select(c => table.Columns[c].SqlName).ToImmutableHashSet(); - return this; - } + /// + /// Uses an explicitly specified set of key column(s). This overrides the UseKeyAttribute option. + /// + /// The column names that form a unique key. + /// + public ObjectDbCommandBuilder WithKeys(params string[] columnNames) + { + var table = OnGetTable(); - IObjectDbCommandBuilder IObjectDbCommandBuilder.WithKeys(params string[] columnNames) - { - return WithKeys(columnNames); - } + //normalize the column names. + KeyColumns = columnNames.Select(c => table.Columns[c].SqlName).ToImmutableHashSet(); + return this; + } - /// - /// After executing the operation, refreshes the properties on the argumentValue by reading the updated values from the database. - /// - /// - public ILink WithRefresh() - { - if (ArgumentValue == null) - throw new InvalidOperationException("Cannot use .WithRefresh() if a null argument is provided."); - return new RefreshMaterializer(this).NeverNull(); - } + IObjectDbCommandBuilder IObjectDbCommandBuilder.WithKeys(params string[] columnNames) + { + return WithKeys(columnNames); + } - /// - /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. - /// - /// - protected abstract TableOrViewMetadata OnGetTable(); + /// + /// After executing the operation, refreshes the properties on the argumentValue by reading the updated values from the database. + /// + /// + public ILink WithRefresh() + { + if (ArgumentValue == null) + throw new InvalidOperationException("Cannot use .WithRefresh() if a null argument is provided."); + return new RefreshMaterializer(this).NeverNull(); } + + /// + /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. + /// + /// + protected abstract TableOrViewMetadata OnGetTable(); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ParameterBuilderCallback.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ParameterBuilderCallback.cs index 12729dfed..f5ba6cf86 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ParameterBuilderCallback.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ParameterBuilderCallback.cs @@ -1,17 +1,16 @@ using System.Data.Common; -namespace Tortuga.Chain.CommandBuilders -{ - /// - /// Callback for the parameter builder. - /// - /// The type of the desired DbParameter. - /// The database specific DbType - /// Metadata about the parameter in question. - /// TParameter. - /// For internal use only. - public delegate TParameter ParameterBuilderCallback(SqlBuilderEntry entry) - where TParameter : DbParameter - where TDbType : struct; -} +namespace Tortuga.Chain.CommandBuilders; + +/// +/// Callback for the parameter builder. +/// +/// The type of the desired DbParameter. +/// The database specific DbType +/// Metadata about the parameter in question. +/// TParameter. +/// For internal use only. +public delegate TParameter ParameterBuilderCallback(SqlBuilderEntry entry) + where TParameter : DbParameter + where TDbType : struct; diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ProcedureDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ProcedureDbCommandBuilder`2.cs index 96637f3fa..b5c3d4b46 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ProcedureDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ProcedureDbCommandBuilder`2.cs @@ -2,40 +2,39 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for command builders that represent stored procedures. +/// +public abstract class ProcedureDbCommandBuilder : MultipleTableDbCommandBuilder, IProcedureDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The data source. + protected ProcedureDbCommandBuilder(ICommandDataSource dataSource) + : base(dataSource) + { } + /// - /// This is the base class for command builders that represent stored procedures. + /// Captures the output parameters as a dictionary. /// - public abstract class ProcedureDbCommandBuilder : MultipleTableDbCommandBuilder, IProcedureDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter + /// The output parameters as a dictionary. + /// This will throw an exception if there are no output parameters. + public ILink> AsOutputs() { - /// Initializes a new instance of the class. - /// The data source. - protected ProcedureDbCommandBuilder(ICommandDataSource dataSource) - : base(dataSource) - { } - - /// - /// Captures the output parameters as a dictionary. - /// - /// The output parameters as a dictionary. - /// This will throw an exception if there are no output parameters. - public ILink> AsOutputs() - { - return new AsOutputsMaterializer(this); - } + return new AsOutputsMaterializer(this); + } - /// - /// Captures the output parameters and use them to populate a new object. - /// - /// The type that will hold the output parameters. - /// The output parameters as an object. - /// This will throw an exception if there are no output parameters. - public ILink AsOutputs() where TObject : class, new() - { - return new AsOutputsMaterializer(this); - } + /// + /// Captures the output parameters and use them to populate a new object. + /// + /// The type that will hold the output parameters. + /// The output parameters as an object. + /// This will throw an exception if there are no output parameters. + public ILink AsOutputs() where TObject : class, new() + { + return new AsOutputsMaterializer(this); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ScalarDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ScalarDbCommandBuilder`2.cs index a0b9f3634..7de0e52d7 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ScalarDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/ScalarDbCommandBuilder`2.cs @@ -3,357 +3,356 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for command builders that return one value. +/// +/// The type of the t command type. +/// The type of the t parameter type. +public abstract class ScalarDbCommandBuilder : DbCommandBuilder, IScalarDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// This is the base class for command builders that return one value. - /// - /// The type of the t command type. - /// The type of the t parameter type. - public abstract class ScalarDbCommandBuilder : DbCommandBuilder, IScalarDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter + /// Initializes a new instance of the class. + /// The data source. + protected ScalarDbCommandBuilder(ICommandDataSource dataSource) + : base(dataSource) { - /// Initializes a new instance of the class. - /// The data source. - protected ScalarDbCommandBuilder(ICommandDataSource dataSource) - : base(dataSource) - { - } - - /// - /// Indicates the results should be materialized as a Boolean. - /// - public ILink ToBoolean() => new BooleanMaterializer(this); - - /// - /// Indicates the results should be materialized as a Boolean. - /// - /// Name of the desired column. - public ILink ToBoolean(string columnName) => new BooleanMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Boolean. - /// - public ILink ToBooleanOrNull() => new BooleanOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Boolean. - /// - /// Name of the desired column. - public ILink ToBooleanOrNull(string columnName) => new BooleanOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a byte. - /// - public ILink ToByte() => new ByteMaterializer(this); - - /// - /// Indicates the results should be materialized as a byte. - /// - /// Name of the desired column. - public ILink ToByte(string columnName) => new ByteMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a byte array. - /// - public ILink ToByteArray() => new ByteArrayMaterializer(this); - - /// - /// Indicates the results should be materialized as a byte array. - /// - /// Name of the desired column. - public ILink ToByteArray(string columnName) => new ByteArrayMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a byte array or null. - /// - public ILink ToByteArrayOrNull() => new ByteArrayOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a byte array or null. - /// - /// Name of the desired column. - public ILink ToByteArrayOrNull(string columnName) => new ByteArrayOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable byte. - /// - public ILink ToByteOrNull() => new ByteOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable byte. - /// - /// Name of the desired column. - public ILink ToByteOrNull(string columnName) => new ByteOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a DateTime. - /// - public ILink ToDateTime() => new DateTimeMaterializer(this); - - /// - /// Indicates the results should be materialized as a DateTime. - /// - /// Name of the desired column. - public ILink ToDateTime(string columnName) => new DateTimeMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a DateTimeOffset. - /// - public ILink ToDateTimeOffset() => new DateTimeOffsetMaterializer(this); - - /// - /// Indicates the results should be materialized as a DateTimeOffset. - /// - /// Name of the desired column. - public ILink ToDateTimeOffset(string columnName) => new DateTimeOffsetMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable DateTimeOffset. - /// - public ILink ToDateTimeOffsetOrNull() => new DateTimeOffsetOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable DateTimeOffset. - /// - /// Name of the desired column. - public ILink ToDateTimeOffsetOrNull(string columnName) => new DateTimeOffsetOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable DateTime. - /// - public ILink ToDateTimeOrNull() => new DateTimeOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable DateTime. - /// - /// Name of the desired column. - public ILink ToDateTimeOrNull(string columnName) => new DateTimeOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Decimal. - /// - public ILink ToDecimal() => new DecimalMaterializer(this); - - /// - /// Indicates the results should be materialized as a Decimal. - /// - /// Name of the desired column. - public ILink ToDecimal(string columnName) => new DecimalMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Decimal. - /// - public ILink ToDecimalOrNull() => new DecimalOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Decimal. - /// - /// Name of the desired column. - public ILink ToDecimalOrNull(string columnName) => new DecimalOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Double. - /// - public ILink ToDouble() => new DoubleMaterializer(this); - - /// - /// Indicates the results should be materialized as a Double. - /// - /// Name of the desired column. - public ILink ToDouble(string columnName) => new DoubleMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Double. - /// - public ILink ToDoubleOrNull() => new DoubleOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Double. - /// - /// Name of the desired column. - public ILink ToDoubleOrNull(string columnName) => new DoubleOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Guid. - /// - public ILink ToGuid() => new GuidMaterializer(this); - - /// - /// Indicates the results should be materialized as a Guid. - /// - /// Name of the desired column. - public ILink ToGuid(string columnName) => new GuidMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Guid. - /// - public ILink ToGuidOrNull() => new GuidOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Guid. - /// - public ILink ToGuidOrNull(string columnName) => new GuidOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Int16. - /// - public ILink ToInt16() => new Int16Materializer(this); - - /// - /// Indicates the results should be materialized as a Int16. - /// - /// Name of the desired column. - public ILink ToInt16(string columnName) => new Int16Materializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Int16. - /// - public ILink ToInt16OrNull() => new Int16OrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Int16. - /// - /// Name of the desired column. - public ILink ToInt16OrNull(string columnName) => new Int16OrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Int32. - /// - public ILink ToInt32() => new Int32Materializer(this); - - /// - /// Indicates the results should be materialized as a Int32. - /// - /// Name of the desired column. - public ILink ToInt32(string columnName) => new Int32Materializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Int32. - /// - public ILink ToInt32OrNull() => new Int32OrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Int32. - /// - /// Name of the desired column. - public ILink ToInt32OrNull(string columnName) => new Int32OrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Int64. - /// - public ILink ToInt64() => new Int64Materializer(this); - - /// - /// Indicates the results should be materialized as a Int64. - /// - /// Name of the desired column. - public ILink ToInt64(string columnName) => new Int64Materializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Int64. - /// - public ILink ToInt64OrNull() => new Int64OrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Int64. - /// - /// Name of the desired column. - public ILink ToInt64OrNull(string columnName) => new Int64OrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a Single. - /// - public ILink ToSingle() => new SingleMaterializer(this); - - /// - /// Indicates the results should be materialized as a Single. - /// - /// Name of the desired column. - public ILink ToSingle(string columnName) => new SingleMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable Single. - /// - public ILink ToSingleOrNull() => new SingleOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable Single. - /// - public ILink ToSingleOrNull(string columnName) => new SingleOrNullMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a non-nullable string. - /// - /// - public new ILink ToString() => new StringMaterializer(this); - - /// - /// Indicates the results should be materialized as a non-nullable string. - /// - /// - public ILink ToString(string columnName) => new StringMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable string. - /// - /// - /// Name of the desired column. - public ILink ToStringOrNull(string columnName) => new StringMaterializerOrNull(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable string. - /// - /// - public ILink ToStringOrNull() => new StringMaterializerOrNull(this); - - /// - /// Indicates the results should be materialized as a TimeSpan. - /// - public ILink ToTimeSpan() => new TimeSpanMaterializer(this); - - /// - /// Indicates the results should be materialized as a TimeSpan. - /// - /// Name of the desired column. - public ILink ToTimeSpan(string columnName) => new TimeSpanMaterializer(this, columnName); - - /// - /// Indicates the results should be materialized as a nullable TimeSpan. - /// - public ILink ToTimeSpanOrNull() => new TimeSpanOrNullMaterializer(this); - - /// - /// Indicates the results should be materialized as a nullable TimeSpan. - /// - /// Name of the desired column. - public ILink ToTimeSpanOrNull(string columnName) => new TimeSpanOrNullMaterializer(this, columnName); - - /// - /// Materializes the result as an XElement. - /// - /// ILink<XElement>. - public ILink ToXml() => new XElementMaterializer(this, null); - - /// - /// Materializes the result as an XElement. - /// - /// Name of the column. - /// ILink<XElement>. - public ILink ToXml(string columnName) => new XElementMaterializer(this, columnName); - - /// - /// Materializes the result as an XElement or null. - /// - /// ILink<XElement>. - public ILink ToXmlOrNull() => new XElementOrNullMaterializer(this, null); - - /// - /// Materializes the result as an XElement or null. - /// - /// Name of the column. - /// ILink<XElement>. - public ILink ToXmlOrNull(string columnName) => new XElementOrNullMaterializer(this, columnName); } + + /// + /// Indicates the results should be materialized as a Boolean. + /// + public ILink ToBoolean() => new BooleanMaterializer(this); + + /// + /// Indicates the results should be materialized as a Boolean. + /// + /// Name of the desired column. + public ILink ToBoolean(string columnName) => new BooleanMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Boolean. + /// + public ILink ToBooleanOrNull() => new BooleanOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Boolean. + /// + /// Name of the desired column. + public ILink ToBooleanOrNull(string columnName) => new BooleanOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a byte. + /// + public ILink ToByte() => new ByteMaterializer(this); + + /// + /// Indicates the results should be materialized as a byte. + /// + /// Name of the desired column. + public ILink ToByte(string columnName) => new ByteMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a byte array. + /// + public ILink ToByteArray() => new ByteArrayMaterializer(this); + + /// + /// Indicates the results should be materialized as a byte array. + /// + /// Name of the desired column. + public ILink ToByteArray(string columnName) => new ByteArrayMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a byte array or null. + /// + public ILink ToByteArrayOrNull() => new ByteArrayOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a byte array or null. + /// + /// Name of the desired column. + public ILink ToByteArrayOrNull(string columnName) => new ByteArrayOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable byte. + /// + public ILink ToByteOrNull() => new ByteOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable byte. + /// + /// Name of the desired column. + public ILink ToByteOrNull(string columnName) => new ByteOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a DateTime. + /// + public ILink ToDateTime() => new DateTimeMaterializer(this); + + /// + /// Indicates the results should be materialized as a DateTime. + /// + /// Name of the desired column. + public ILink ToDateTime(string columnName) => new DateTimeMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a DateTimeOffset. + /// + public ILink ToDateTimeOffset() => new DateTimeOffsetMaterializer(this); + + /// + /// Indicates the results should be materialized as a DateTimeOffset. + /// + /// Name of the desired column. + public ILink ToDateTimeOffset(string columnName) => new DateTimeOffsetMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable DateTimeOffset. + /// + public ILink ToDateTimeOffsetOrNull() => new DateTimeOffsetOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable DateTimeOffset. + /// + /// Name of the desired column. + public ILink ToDateTimeOffsetOrNull(string columnName) => new DateTimeOffsetOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable DateTime. + /// + public ILink ToDateTimeOrNull() => new DateTimeOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable DateTime. + /// + /// Name of the desired column. + public ILink ToDateTimeOrNull(string columnName) => new DateTimeOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Decimal. + /// + public ILink ToDecimal() => new DecimalMaterializer(this); + + /// + /// Indicates the results should be materialized as a Decimal. + /// + /// Name of the desired column. + public ILink ToDecimal(string columnName) => new DecimalMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Decimal. + /// + public ILink ToDecimalOrNull() => new DecimalOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Decimal. + /// + /// Name of the desired column. + public ILink ToDecimalOrNull(string columnName) => new DecimalOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Double. + /// + public ILink ToDouble() => new DoubleMaterializer(this); + + /// + /// Indicates the results should be materialized as a Double. + /// + /// Name of the desired column. + public ILink ToDouble(string columnName) => new DoubleMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Double. + /// + public ILink ToDoubleOrNull() => new DoubleOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Double. + /// + /// Name of the desired column. + public ILink ToDoubleOrNull(string columnName) => new DoubleOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Guid. + /// + public ILink ToGuid() => new GuidMaterializer(this); + + /// + /// Indicates the results should be materialized as a Guid. + /// + /// Name of the desired column. + public ILink ToGuid(string columnName) => new GuidMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Guid. + /// + public ILink ToGuidOrNull() => new GuidOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Guid. + /// + public ILink ToGuidOrNull(string columnName) => new GuidOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Int16. + /// + public ILink ToInt16() => new Int16Materializer(this); + + /// + /// Indicates the results should be materialized as a Int16. + /// + /// Name of the desired column. + public ILink ToInt16(string columnName) => new Int16Materializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Int16. + /// + public ILink ToInt16OrNull() => new Int16OrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Int16. + /// + /// Name of the desired column. + public ILink ToInt16OrNull(string columnName) => new Int16OrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Int32. + /// + public ILink ToInt32() => new Int32Materializer(this); + + /// + /// Indicates the results should be materialized as a Int32. + /// + /// Name of the desired column. + public ILink ToInt32(string columnName) => new Int32Materializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Int32. + /// + public ILink ToInt32OrNull() => new Int32OrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Int32. + /// + /// Name of the desired column. + public ILink ToInt32OrNull(string columnName) => new Int32OrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Int64. + /// + public ILink ToInt64() => new Int64Materializer(this); + + /// + /// Indicates the results should be materialized as a Int64. + /// + /// Name of the desired column. + public ILink ToInt64(string columnName) => new Int64Materializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Int64. + /// + public ILink ToInt64OrNull() => new Int64OrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Int64. + /// + /// Name of the desired column. + public ILink ToInt64OrNull(string columnName) => new Int64OrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a Single. + /// + public ILink ToSingle() => new SingleMaterializer(this); + + /// + /// Indicates the results should be materialized as a Single. + /// + /// Name of the desired column. + public ILink ToSingle(string columnName) => new SingleMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable Single. + /// + public ILink ToSingleOrNull() => new SingleOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable Single. + /// + public ILink ToSingleOrNull(string columnName) => new SingleOrNullMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a non-nullable string. + /// + /// + public new ILink ToString() => new StringMaterializer(this); + + /// + /// Indicates the results should be materialized as a non-nullable string. + /// + /// + public ILink ToString(string columnName) => new StringMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable string. + /// + /// + /// Name of the desired column. + public ILink ToStringOrNull(string columnName) => new StringMaterializerOrNull(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable string. + /// + /// + public ILink ToStringOrNull() => new StringMaterializerOrNull(this); + + /// + /// Indicates the results should be materialized as a TimeSpan. + /// + public ILink ToTimeSpan() => new TimeSpanMaterializer(this); + + /// + /// Indicates the results should be materialized as a TimeSpan. + /// + /// Name of the desired column. + public ILink ToTimeSpan(string columnName) => new TimeSpanMaterializer(this, columnName); + + /// + /// Indicates the results should be materialized as a nullable TimeSpan. + /// + public ILink ToTimeSpanOrNull() => new TimeSpanOrNullMaterializer(this); + + /// + /// Indicates the results should be materialized as a nullable TimeSpan. + /// + /// Name of the desired column. + public ILink ToTimeSpanOrNull(string columnName) => new TimeSpanOrNullMaterializer(this, columnName); + + /// + /// Materializes the result as an XElement. + /// + /// ILink<XElement>. + public ILink ToXml() => new XElementMaterializer(this, null); + + /// + /// Materializes the result as an XElement. + /// + /// Name of the column. + /// ILink<XElement>. + public ILink ToXml(string columnName) => new XElementMaterializer(this, columnName); + + /// + /// Materializes the result as an XElement or null. + /// + /// ILink<XElement>. + public ILink ToXmlOrNull() => new XElementOrNullMaterializer(this, null); + + /// + /// Materializes the result as an XElement or null. + /// + /// Name of the column. + /// ILink<XElement>. + public ILink ToXmlOrNull(string columnName) => new XElementOrNullMaterializer(this, columnName); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`2.cs index a0857e07b..f35cd54cd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`2.cs @@ -2,80 +2,79 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for command builders that can potentially return one row. +/// +/// The type of the t command type. +/// The type of the t parameter type. +public abstract class SingleRowDbCommandBuilder : ScalarDbCommandBuilder, ISingleRowDbCommandBuilder +where TCommand : DbCommand +where TParameter : DbParameter { - /// - /// This is the base class for command builders that can potentially return one row. - /// - /// The type of the t command type. - /// The type of the t parameter type. - public abstract class SingleRowDbCommandBuilder : ScalarDbCommandBuilder, ISingleRowDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter + /// Initializes a new instance of the class. + /// The data source. + protected SingleRowDbCommandBuilder(ICommandDataSource dataSource) + : base(dataSource) { - /// Initializes a new instance of the class. - /// The data source. - protected SingleRowDbCommandBuilder(ICommandDataSource dataSource) - : base(dataSource) - { - } + } - /// - /// Indicates the results should be materialized as a Row. - /// - public ILink ToDataRow(RowOptions rowOptions = RowOptions.None) => new DataRowMaterializer(this, rowOptions); + /// + /// Indicates the results should be materialized as a Row. + /// + public ILink ToDataRow(RowOptions rowOptions = RowOptions.None) => new DataRowMaterializer(this, rowOptions); - /// - /// Indicates the results should be materialized as a Row. - /// - public ILink ToDataRowOrNull(RowOptions rowOptions = RowOptions.None) => new DataRowOrNullMaterializer(this, rowOptions); + /// + /// Indicates the results should be materialized as a Row. + /// + public ILink ToDataRowOrNull(RowOptions rowOptions = RowOptions.None) => new DataRowOrNullMaterializer(this, rowOptions); - /// - /// Materializes the result as a dynamic object - /// - /// The row options. - /// - public ILink ToDynamicObject(RowOptions rowOptions = RowOptions.None) => new DynamicObjectMaterializer(this, rowOptions); + /// + /// Materializes the result as a dynamic object + /// + /// The row options. + /// + public ILink ToDynamicObject(RowOptions rowOptions = RowOptions.None) => new DynamicObjectMaterializer(this, rowOptions); - /// - /// Materializes the result as a dynamic object - /// - /// The row options. - /// - public ILink ToDynamicObjectOrNull(RowOptions rowOptions = RowOptions.None) => new DynamicObjectOrNullMaterializer(this, rowOptions); + /// + /// Materializes the result as a dynamic object + /// + /// The row options. + /// + public ILink ToDynamicObjectOrNull(RowOptions rowOptions = RowOptions.None) => new DynamicObjectOrNullMaterializer(this, rowOptions); - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) - where TObject : class - { - return new ObjectMaterializer(this, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) + where TObject : class + { + return new ObjectMaterializer(this, rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The type of the object returned. - /// The row options. - /// - public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - where TObject : class - { - return new ObjectOrNullMaterializer(this, rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The type of the object returned. + /// The row options. + /// + public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + where TObject : class + { + return new ObjectOrNullMaterializer(this, rowOptions); + } - /// - /// Indicates the results should be materialized as a Row. - /// - public ILink ToRow(RowOptions rowOptions = RowOptions.None) => new RowMaterializer(this, rowOptions); + /// + /// Indicates the results should be materialized as a Row. + /// + public ILink ToRow(RowOptions rowOptions = RowOptions.None) => new RowMaterializer(this, rowOptions); - /// - /// Indicates the results should be materialized as a Row. - /// - public ILink ToRowOrNull(RowOptions rowOptions = RowOptions.None) => new RowOrNullMaterializer(this, rowOptions); - } + /// + /// Indicates the results should be materialized as a Row. + /// + public ILink ToRowOrNull(RowOptions rowOptions = RowOptions.None) => new RowOrNullMaterializer(this, rowOptions); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`3.cs index d90da0390..b585283cc 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SingleRowDbCommandBuilder`3.cs @@ -3,80 +3,79 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// Class SingleRowDbCommandBuilder is an adapter used to add a return type for subclasses of SingleRowDbCommandBuilder{TCommand, TParameter}. +/// +/// The type of the t command. +/// The type of the t parameter. +/// The type of the t object. +public class SingleRowDbCommandBuilder : SingleRowDbCommandBuilder, ISingleRowDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class { + readonly SingleRowDbCommandBuilder m_CommandBuilder; + /// - /// Class SingleRowDbCommandBuilder is an adapter used to add a return type for subclasses of SingleRowDbCommandBuilder{TCommand, TParameter}. + /// Initializes a new instance of the class. /// - /// The type of the t command. - /// The type of the t parameter. - /// The type of the t object. - public class SingleRowDbCommandBuilder : SingleRowDbCommandBuilder, ISingleRowDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class + /// The command builder. + /// commandBuilder + public SingleRowDbCommandBuilder(SingleRowDbCommandBuilder commandBuilder) + : base(commandBuilder?.DataSource ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null.")) { - readonly SingleRowDbCommandBuilder m_CommandBuilder; - - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// commandBuilder - public SingleRowDbCommandBuilder(SingleRowDbCommandBuilder commandBuilder) - : base(commandBuilder?.DataSource ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null.")) - { - m_CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); - } + m_CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - return m_CommandBuilder.Prepare(materializer); - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + return m_CommandBuilder.Prepare(materializer); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// IConstructibleMaterializer<TObject>. - public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) - { - return m_CommandBuilder.ToObject(rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// IConstructibleMaterializer<TObject>. + public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) + { + return m_CommandBuilder.ToObject(rowOptions); + } - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// IConstructibleMaterializer<TObject>. - public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - { - return m_CommandBuilder.ToObjectOrNull(rowOptions); - } + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// IConstructibleMaterializer<TObject>. + public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + { + return m_CommandBuilder.ToObjectOrNull(rowOptions); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// If the column name was not found, this will return null - public override ColumnMetadata? TryGetColumn(string columnName) - { - return m_CommandBuilder.TryGetColumn(columnName); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// If the column name was not found, this will return null + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_CommandBuilder.TryGetColumn(columnName); + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// This is used by materializers to skip IsNull checks. - public override IReadOnlyList TryGetNonNullableColumns() - { - return m_CommandBuilder.TryGetNonNullableColumns(); - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// This is used by materializers to skip IsNull checks. + public override IReadOnlyList TryGetNonNullableColumns() + { + return m_CommandBuilder.TryGetNonNullableColumns(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder.cs index e0704c3d5..b7c639dc6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder.cs @@ -3,89 +3,88 @@ using System.Globalization; using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// Helper functions for building SQL statements. +/// +public static class SqlBuilder { /// - /// Helper functions for building SQL statements. + /// Checks to see of the same property appears in both objects. If it does, an InvalidOperationException is thrown with the provided error message. /// - public static class SqlBuilder + /// The first object. + /// The second object. + /// The error format. Slot 0 is the matching property. + /// System.String. + /// If either object is null, this check is skipped. + [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "object")] + public static void CheckForOverlaps(object? firstObject, object? secondObject, string errorFormat) { - /// - /// Checks to see of the same property appears in both objects. If it does, an InvalidOperationException is thrown with the provided error message. - /// - /// The first object. - /// The second object. - /// The error format. Slot 0 is the matching property. - /// System.String. - /// If either object is null, this check is skipped. - [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "object")] - public static void CheckForOverlaps(object? firstObject, object? secondObject, string errorFormat) - { - if (firstObject == null) - return; - if (secondObject == null) - return; + if (firstObject == null) + return; + if (secondObject == null) + return; - var leftList = MetadataCache.GetMetadata(firstObject.GetType()).Properties; - var rightList = MetadataCache.GetMetadata(secondObject.GetType()).Properties; - foreach (var property1 in leftList) - foreach (var property2 in rightList) - if (property1.Name.Equals(property2.Name, StringComparison.OrdinalIgnoreCase)) - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, errorFormat, property1.Name)); - } + var leftList = MetadataCache.GetMetadata(firstObject.GetType()).Properties; + var rightList = MetadataCache.GetMetadata(secondObject.GetType()).Properties; + foreach (var property1 in leftList) + foreach (var property2 in rightList) + if (property1.Name.Equals(property2.Name, StringComparison.OrdinalIgnoreCase)) + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, errorFormat, property1.Name)); + } - /// - /// Gets parameters from an argument value. - /// - /// The type of the parameter. - /// The argument value . - /// - [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] - public static List GetParameters(object? argumentValue) - where TParameter : DbParameter, new() - { - return GetParameters(argumentValue, () => new TParameter()); - } + /// + /// Gets parameters from an argument value. + /// + /// The type of the parameter. + /// The argument value . + /// + [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] + public static List GetParameters(object? argumentValue) + where TParameter : DbParameter, new() + { + return GetParameters(argumentValue, () => new TParameter()); + } - /// - /// Gets parameters from an argument value. - /// - /// The type of the parameter. - /// The argument value . - /// The parameter builder. This should set the parameter's database specific DbType property. - /// - [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] - public static List GetParameters(object? argumentValue, Func parameterBuilder) - where TParameter : DbParameter - { - if (parameterBuilder == null) - throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); + /// + /// Gets parameters from an argument value. + /// + /// The type of the parameter. + /// The argument value . + /// The parameter builder. This should set the parameter's database specific DbType property. + /// + [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] + public static List GetParameters(object? argumentValue, Func parameterBuilder) + where TParameter : DbParameter + { + if (parameterBuilder == null) + throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); - var result = new List(); + var result = new List(); - if (argumentValue is TParameter parameter) - result.Add(parameter); - else if (argumentValue is IEnumerable parameters) - foreach (var param in parameters) - result.Add(param); - else if (argumentValue is IReadOnlyDictionary readOnlyDictionary) - foreach (var item in readOnlyDictionary) - { - var param = parameterBuilder(); - param.ParameterName = (item.Key.StartsWith("@", StringComparison.OrdinalIgnoreCase)) ? item.Key : "@" + item.Key; - param.Value = item.Value ?? DBNull.Value; - result.Add(param); - } - else if (argumentValue != null) - foreach (var property in MetadataCache.GetMetadata(argumentValue.GetType()).Properties.Where(x => x.MappedColumnName != null)) - { - var param = parameterBuilder(); - param.ParameterName = (property.MappedColumnName!.StartsWith("@", StringComparison.OrdinalIgnoreCase)) ? property.MappedColumnName : "@" + property.MappedColumnName; - param.Value = property.InvokeGet(argumentValue) ?? DBNull.Value; - result.Add(param); - } + if (argumentValue is TParameter parameter) + result.Add(parameter); + else if (argumentValue is IEnumerable parameters) + foreach (var param in parameters) + result.Add(param); + else if (argumentValue is IReadOnlyDictionary readOnlyDictionary) + foreach (var item in readOnlyDictionary) + { + var param = parameterBuilder(); + param.ParameterName = (item.Key.StartsWith("@", StringComparison.OrdinalIgnoreCase)) ? item.Key : "@" + item.Key; + param.Value = item.Value ?? DBNull.Value; + result.Add(param); + } + else if (argumentValue != null) + foreach (var property in MetadataCache.GetMetadata(argumentValue.GetType()).Properties.Where(x => x.MappedColumnName != null)) + { + var param = parameterBuilder(); + param.ParameterName = (property.MappedColumnName!.StartsWith("@", StringComparison.OrdinalIgnoreCase)) ? property.MappedColumnName : "@" + property.MappedColumnName; + param.Value = property.InvokeGet(argumentValue) ?? DBNull.Value; + result.Add(param); + } - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilderEntry`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilderEntry`1.cs index dd6439ee7..fb5f871cb 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilderEntry`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilderEntry`1.cs @@ -1,257 +1,256 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders -{ - /// Struct SqlBuilderEntry - /// The type of the database type. - /// This is a struct because we want fast allocations and copies. Try to keep it at 16 bytes or less. - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct SqlBuilderEntry - where TDbType : struct - { - Flags m_Flags; - - [Flags] - internal enum Flags : ushort //this is internal, so we can make it larger if needed - { - None = 0, - IsFormalParameter = 1, - UseForInsert = 2, - IsKey = 4, - UseForRead = 8, - UseForUpdate = 16, - UseParameter = 32, - RestrictedRead = 64, - RestrictedInsert = 128, - RestrictedUpdate = 256, +namespace Tortuga.Chain.CommandBuilders; - /// - /// This allows the parameter to be used a second time. It is needed when using anonymous parameters. - /// - UseParameter2 = 512, +/// Struct SqlBuilderEntry +/// The type of the database type. +/// This is a struct because we want fast allocations and copies. Try to keep it at 16 bytes or less. +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct SqlBuilderEntry + where TDbType : struct +{ + Flags m_Flags; - /// - /// The use Clr name as alias when reading. Used for object materialization purposes. - /// - UseClrNameAsAlias = 1024 - } + [Flags] + internal enum Flags : ushort //this is internal, so we can make it larger if needed + { + None = 0, + IsFormalParameter = 1, + UseForInsert = 2, + IsKey = 4, + UseForRead = 8, + UseForUpdate = 16, + UseParameter = 32, + RestrictedRead = 64, + RestrictedInsert = 128, + RestrictedUpdate = 256, /// - /// Gets or sets the immutable column metadata. + /// This allows the parameter to be used a second time. It is needed when using anonymous parameters. /// - /// - /// The column. - /// - public ISqlBuilderEntryDetails Details { get; set; } + UseParameter2 = 512, /// - /// Gets a value indicating whether this instance is an output parameter. + /// The use Clr name as alias when reading. Used for object materialization purposes. /// - public bool IsOutputParameter => - Details.Direction == ParameterDirection.InputOutput || Details.Direction == ParameterDirection.Output; + UseClrNameAsAlias = 1024 + } - /// - /// Gets or sets a value indicating whether this is a formal parameter for a stored procedure or table value function. - /// - /// - /// true if [formal parameter]; otherwise, false. - /// - public bool IsFormalParameter + /// + /// Gets or sets the immutable column metadata. + /// + /// + /// The column. + /// + public ISqlBuilderEntryDetails Details { get; set; } + + /// + /// Gets or sets a value indicating whether this is a formal parameter for a stored procedure or table value function. + /// + /// + /// true if [formal parameter]; otherwise, false. + /// + public bool IsFormalParameter + { + get { return (m_Flags & Flags.IsFormalParameter) > 0; } + internal set { - get { return (m_Flags & Flags.IsFormalParameter) > 0; } - internal set - { - if (value) - m_Flags |= Flags.IsFormalParameter; - else - m_Flags &= ~Flags.IsFormalParameter; - } + if (value) + m_Flags |= Flags.IsFormalParameter; + else + m_Flags &= ~Flags.IsFormalParameter; } + } - /// - /// Gets or sets a value indicating whether this column should be treated as primary key. - /// - /// - /// true if this instance is primary key; otherwise, false. - /// - /// - /// This can be overridden. For example, if the parameter object defines its own alternate keys. - /// - public bool IsKey + /// + /// Gets or sets a value indicating whether this column should be treated as primary key. + /// + /// + /// true if this instance is primary key; otherwise, false. + /// + /// + /// This can be overridden. For example, if the parameter object defines its own alternate keys. + /// + public bool IsKey + { + get { return (m_Flags & Flags.IsKey) > 0; } + internal set { - get { return (m_Flags & Flags.IsKey) > 0; } - internal set - { - if (value) - m_Flags |= Flags.IsKey; - else - m_Flags &= ~Flags.IsKey; - } + if (value) + m_Flags |= Flags.IsKey; + else + m_Flags &= ~Flags.IsKey; } + } - /// - /// When non-null, this indicates that we want to use a table value parameter instead of a normal parameter. - /// - public ISqlBuilderEntryDetails? ParameterColumn { get; set; } + /// + /// Gets a value indicating whether this instance is an output parameter. + /// + public bool IsOutputParameter => + Details.Direction == ParameterDirection.InputOutput || Details.Direction == ParameterDirection.Output; - /// - /// Gets or sets the value to be used when constructing parameters. - /// - /// - /// The parameter value. - /// - /// A null means this parameter's value was not set. A DBNull.Value means it is passed to the database as a null. - public object? ParameterValue { get; set; } + /// + /// When non-null, this indicates that we want to use a table value parameter instead of a normal parameter. + /// + public ISqlBuilderEntryDetails? ParameterColumn { get; set; } - /// - /// Gets a value indicating whether restricted from inserting. - /// - public bool RestrictedInsert + /// + /// Gets or sets the value to be used when constructing parameters. + /// + /// + /// The parameter value. + /// + /// A null means this parameter's value was not set. A DBNull.Value means it is passed to the database as a null. + public object? ParameterValue { get; set; } + + /// + /// Gets a value indicating whether restricted from inserting. + /// + public bool RestrictedInsert + { + get { return (m_Flags & Flags.RestrictedInsert) > 0; } + internal set { - get { return (m_Flags & Flags.RestrictedInsert) > 0; } - internal set - { - if (value) - m_Flags |= Flags.RestrictedInsert; - else - m_Flags &= ~Flags.RestrictedInsert; - } + if (value) + m_Flags |= Flags.RestrictedInsert; + else + m_Flags &= ~Flags.RestrictedInsert; } + } - /// - /// Gets a value indicating whether restricted from reading. - /// - public bool RestrictedRead + /// + /// Gets a value indicating whether restricted from reading. + /// + public bool RestrictedRead + { + get { return (m_Flags & Flags.RestrictedRead) > 0; } + internal set { - get { return (m_Flags & Flags.RestrictedRead) > 0; } - internal set - { - if (value) - m_Flags |= Flags.RestrictedRead; - else - m_Flags &= ~Flags.RestrictedRead; - } + if (value) + m_Flags |= Flags.RestrictedRead; + else + m_Flags &= ~Flags.RestrictedRead; } + } - /// - /// Gets a value indicating whether restricted from updating. - /// - public bool RestrictedUpdate + /// + /// Gets a value indicating whether restricted from updating. + /// + public bool RestrictedUpdate + { + get { return (m_Flags & Flags.RestrictedUpdate) > 0; } + internal set { - get { return (m_Flags & Flags.RestrictedUpdate) > 0; } - internal set - { - if (value) - m_Flags |= Flags.RestrictedUpdate; - else - m_Flags &= ~Flags.RestrictedUpdate; - } + if (value) + m_Flags |= Flags.RestrictedUpdate; + else + m_Flags &= ~Flags.RestrictedUpdate; } + } - /// - /// Gets a value indicating whether the SQL generator should produce an AS clause for this column. - /// - /// This is used when the actual column name doesn't match the CLR-compatible version of the column name. This could happen when the real column name has spaces. - public bool UseClrNameAsAlias + /// + /// Gets a value indicating whether the SQL generator should produce an AS clause for this column. + /// + /// This is used when the actual column name doesn't match the CLR-compatible version of the column name. This could happen when the real column name has spaces. + public bool UseClrNameAsAlias + { + get { return (m_Flags & Flags.UseClrNameAsAlias) > 0; } + internal set { - get { return (m_Flags & Flags.UseClrNameAsAlias) > 0; } - internal set - { - if (value) - m_Flags |= Flags.UseClrNameAsAlias; - else - m_Flags &= ~Flags.UseClrNameAsAlias; - } + if (value) + m_Flags |= Flags.UseClrNameAsAlias; + else + m_Flags &= ~Flags.UseClrNameAsAlias; } + } - /// - /// Gets or sets a value indicating whether this participates in insert operations. - /// - /// - /// true if insert; otherwise, false. - /// - public bool UseForInsert + /// + /// Gets or sets a value indicating whether this participates in insert operations. + /// + /// + /// true if insert; otherwise, false. + /// + public bool UseForInsert + { + get { return (m_Flags & Flags.UseForInsert) > 0; } + internal set { - get { return (m_Flags & Flags.UseForInsert) > 0; } - internal set - { - if (value) - m_Flags |= Flags.UseForInsert; - else - m_Flags &= ~Flags.UseForInsert; - } + if (value) + m_Flags |= Flags.UseForInsert; + else + m_Flags &= ~Flags.UseForInsert; } + } - /// - /// Gets or sets a value indicating whether this participates in read operations. - /// - /// - /// true if read; otherwise, false. - /// - public bool UseForRead + /// + /// Gets or sets a value indicating whether this participates in read operations. + /// + /// + /// true if read; otherwise, false. + /// + public bool UseForRead + { + get { return (m_Flags & Flags.UseForRead) > 0; } + internal set { - get { return (m_Flags & Flags.UseForRead) > 0; } - internal set - { - if (value) - m_Flags |= Flags.UseForRead; - else - m_Flags &= ~Flags.UseForRead; - } + if (value) + m_Flags |= Flags.UseForRead; + else + m_Flags &= ~Flags.UseForRead; } + } - /// - /// Gets or sets a value indicating whether this participates in update operations. - /// - /// - /// true if update; otherwise, false. - /// - public bool UseForUpdate + /// + /// Gets or sets a value indicating whether this participates in update operations. + /// + /// + /// true if update; otherwise, false. + /// + public bool UseForUpdate + { + get { return (m_Flags & Flags.UseForUpdate) > 0; } + internal set { - get { return (m_Flags & Flags.UseForUpdate) > 0; } - internal set - { - if (value) - m_Flags |= Flags.UseForUpdate; - else - m_Flags &= ~Flags.UseForUpdate; - } + if (value) + m_Flags |= Flags.UseForUpdate; + else + m_Flags &= ~Flags.UseForUpdate; } + } - /// - /// Gets or sets a value indicating whether this participates in parameter generation. - /// - /// - /// true if [use parameter]; otherwise, false. - /// - public bool UseParameter + /// + /// Gets or sets a value indicating whether this participates in parameter generation. + /// + /// + /// true if [use parameter]; otherwise, false. + /// + public bool UseParameter + { + get { return (m_Flags & Flags.UseParameter) > 0; } + internal set { - get { return (m_Flags & Flags.UseParameter) > 0; } - internal set - { - if (value) - m_Flags |= Flags.UseParameter; - else - m_Flags &= ~Flags.UseParameter; - } + if (value) + m_Flags |= Flags.UseParameter; + else + m_Flags &= ~Flags.UseParameter; } + } - /// - /// Gets or sets a value indicating whether this participates in the second pass of parameter generation. - /// - /// true if [use parameter2]; otherwise, false. - /// This is needed when referencing anonymous parameters. - public bool UseParameter2 + /// + /// Gets or sets a value indicating whether this participates in the second pass of parameter generation. + /// + /// true if [use parameter2]; otherwise, false. + /// This is needed when referencing anonymous parameters. + public bool UseParameter2 + { + get { return (m_Flags & Flags.UseParameter2) > 0; } + internal set { - get { return (m_Flags & Flags.UseParameter2) > 0; } - internal set - { - if (value) - m_Flags |= Flags.UseParameter2; - else - m_Flags &= ~Flags.UseParameter2; - } + if (value) + m_Flags |= Flags.UseParameter2; + else + m_Flags &= ~Flags.UseParameter2; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder`1.cs index 4a346b318..3ab0c8385 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/SqlBuilder`1.cs @@ -9,1597 +9,1596 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// Class SqlBuilder. This class cannot be inherited. +/// The type of the database type. +public sealed class SqlBuilder + where TDbType : struct { - /// Class SqlBuilder. This class cannot be inherited. - /// The type of the database type. - public sealed class SqlBuilder - where TDbType : struct - { - readonly SqlBuilderEntry[] m_Entries; + readonly SqlBuilderEntry[] m_Entries; - readonly string m_Name; + readonly string m_Name; - internal SqlBuilder(string name, IReadOnlyList> columns, IReadOnlyList> parameters) - { - m_Name = name; + internal SqlBuilder(string name, IReadOnlyList> columns, IReadOnlyList> parameters) + { + m_Name = name; - m_Entries = new SqlBuilderEntry[columns.Count + parameters.Count]; + m_Entries = new SqlBuilderEntry[columns.Count + parameters.Count]; - for (int i = 0; i < columns.Count; i++) + for (int i = 0; i < columns.Count; i++) + { + var column = columns[i]; + m_Entries[i] = new SqlBuilderEntry() { - var column = columns[i]; - m_Entries[i] = new SqlBuilderEntry() - { - Details = column, - IsKey = column.IsPrimaryKey, - UseForInsert = !column.IsComputed && !column.IsIdentity, - UseForUpdate = !column.IsComputed && !column.IsIdentity - }; - } + Details = column, + IsKey = column.IsPrimaryKey, + UseForInsert = !column.IsComputed && !column.IsIdentity, + UseForUpdate = !column.IsComputed && !column.IsIdentity + }; + } - var offset = columns.Count; - for (int i = 0; i < parameters.Count; i++) + var offset = columns.Count; + for (int i = 0; i < parameters.Count; i++) + { + var column = parameters[i]; + m_Entries[offset + i] = new SqlBuilderEntry() { - var column = parameters[i]; - m_Entries[offset + i] = new SqlBuilderEntry() - { - Details = column, - IsFormalParameter = true - }; - } + Details = column, + IsFormalParameter = true + }; } + } - internal SqlBuilder(string name, IReadOnlyList> columns) - { - m_Name = name; + internal SqlBuilder(string name, IReadOnlyList> columns) + { + m_Name = name; - m_Entries = new SqlBuilderEntry[columns.Count]; + m_Entries = new SqlBuilderEntry[columns.Count]; - for (int i = 0; i < columns.Count; i++) + for (int i = 0; i < columns.Count; i++) + { + var column = columns[i]; + m_Entries[i] = new SqlBuilderEntry() { - var column = columns[i]; - m_Entries[i] = new SqlBuilderEntry() - { - Details = column, - IsKey = column.IsPrimaryKey, - UseForInsert = !column.IsComputed && !column.IsIdentity, - UseForUpdate = !column.IsComputed && !column.IsIdentity - }; - } + Details = column, + IsKey = column.IsPrimaryKey, + UseForInsert = !column.IsComputed && !column.IsIdentity, + UseForUpdate = !column.IsComputed && !column.IsIdentity + }; } + } - internal SqlBuilder(string name, IReadOnlyList> parameters) - { - m_Name = name; + internal SqlBuilder(string name, IReadOnlyList> parameters) + { + m_Name = name; - m_Entries = new SqlBuilderEntry[parameters.Count]; - for (int i = 0; i < parameters.Count; i++) + m_Entries = new SqlBuilderEntry[parameters.Count]; + for (int i = 0; i < parameters.Count; i++) + { + var column = parameters[i]; + m_Entries[i] = new SqlBuilderEntry() { - var column = parameters[i]; - m_Entries[i] = new SqlBuilderEntry() - { - Details = column, - IsFormalParameter = true - }; - } + Details = column, + IsFormalParameter = true + }; } + } - SqlBuilder(string name, SqlBuilderEntry[] entries, bool strictMode) - { - m_Name = name; - m_Entries = entries.ToArray(); //since this is an array of struct, this does a deep copy - StrictMode = strictMode; - } + SqlBuilder(string name, SqlBuilderEntry[] entries, bool strictMode) + { + m_Name = name; + m_Entries = entries.ToArray(); //since this is an array of struct, this does a deep copy + StrictMode = strictMode; + } - /// - /// Gets a value indicating whether this instance has fields marked for reading. - /// - /// - /// true if this instance has read fields; otherwise, false. - /// - public bool HasReadFields + /// + /// Gets a value indicating whether this instance has fields marked for reading. + /// + /// + /// true if this instance has read fields; otherwise, false. + /// + public bool HasReadFields + { + get { - get - { - for (var i = 0; i < m_Entries.Length; i++) - if (m_Entries[i].UseForRead) - return true; - return false; - } + for (var i = 0; i < m_Entries.Length; i++) + if (m_Entries[i].UseForRead) + return true; + return false; } + } - /// - /// Gets a value indicating whether strict mode is enabled - /// - public bool StrictMode { get; } - - /// - /// Applies the filter value, returning a set of expressions suitable for use in a WHERE clause. - /// - /// The filter value. - /// The filter options. - /// if set to true uses the second parameter slot. - /// System.String. - /// filterValue - filterValue - /// - /// - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public string ApplyAnonymousFilterValue(object filterValue, FilterOptions filterOptions, bool useSecondSlot = false) - { - if (filterValue == null) - throw new ArgumentNullException(nameof(filterValue), $"{nameof(filterValue)} is null."); + /// + /// Gets a value indicating whether strict mode is enabled + /// + public bool StrictMode { get; } + + /// + /// Applies the filter value, returning a set of expressions suitable for use in a WHERE clause. + /// + /// The filter value. + /// The filter options. + /// if set to true uses the second parameter slot. + /// System.String. + /// filterValue - filterValue + /// + /// + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public string ApplyAnonymousFilterValue(object filterValue, FilterOptions filterOptions, bool useSecondSlot = false) + { + if (filterValue == null) + throw new ArgumentNullException(nameof(filterValue), $"{nameof(filterValue)} is null."); - var ignoreNullProperties = filterOptions.HasFlag(FilterOptions.IgnoreNullProperties); - var parts = new string[m_Entries.Length]; - bool found = false; + var ignoreNullProperties = filterOptions.HasFlag(FilterOptions.IgnoreNullProperties); + var parts = new string[m_Entries.Length]; + bool found = false; - if (filterValue is IReadOnlyDictionary readOnlyDictionary) + if (filterValue is IReadOnlyDictionary readOnlyDictionary) + { + foreach (var item in readOnlyDictionary) { - foreach (var item in readOnlyDictionary) + var keyFound = false; + for (var i = 0; i < m_Entries.Length; i++) { - var keyFound = false; - for (var i = 0; i < m_Entries.Length; i++) + ref var entry = ref m_Entries[i]; + + if (string.Equals(entry.Details.ClrName, item.Key, StringComparison.OrdinalIgnoreCase) + || string.Equals(entry.Details.SqlName, item.Key, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; + var value = item.Value ?? DBNull.Value; - if (string.Equals(entry.Details.ClrName, item.Key, StringComparison.OrdinalIgnoreCase) - || string.Equals(entry.Details.SqlName, item.Key, StringComparison.OrdinalIgnoreCase)) + if (value == DBNull.Value) { - var value = item.Value ?? DBNull.Value; - - if (value == DBNull.Value) - { - if (!ignoreNullProperties) - parts[i] = ($"{entry.Details.QuotedSqlName} IS NULL"); - } + if (!ignoreNullProperties) + parts[i] = ($"{entry.Details.QuotedSqlName} IS NULL"); + } + else + { + entry.ParameterValue = value; + if (!useSecondSlot) + entry.UseParameter = true; else - { - entry.ParameterValue = value; - if (!useSecondSlot) - entry.UseParameter = true; - else - entry.UseParameter2 = true; - parts[i] = ($"{entry.Details.QuotedSqlName} = ?"); - } - - found = true; - keyFound = true; - break; + entry.UseParameter2 = true; + parts[i] = ($"{entry.Details.QuotedSqlName} = ?"); } + + found = true; + keyFound = true; + break; } - if (StrictMode && !keyFound) - throw new MappingException($"Strict mode was enabled, but property {item.Key} could be matched to a column in {m_Name}. Disable strict mode or remove the item from the dictionary."); } + if (StrictMode && !keyFound) + throw new MappingException($"Strict mode was enabled, but property {item.Key} could be matched to a column in {m_Name}. Disable strict mode or remove the item from the dictionary."); } - else + } + else + { + foreach (var property in MetadataCache.GetMetadata(filterValue.GetType()).Properties.Where(p => p.MappedColumnName != null && p.CanRead)) { - foreach (var property in MetadataCache.GetMetadata(filterValue.GetType()).Properties.Where(p => p.MappedColumnName != null)) + var propertyFound = false; + for (var i = 0; i < m_Entries.Length; i++) { - var propertyFound = false; - for (var i = 0; i < m_Entries.Length; i++) + ref var entry = ref m_Entries[i]; + + if (entry.Details.ClrName.Equals(property.MappedColumnName, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; + var value = property.InvokeGet(filterValue) ?? DBNull.Value; - if (entry.Details.ClrName.Equals(property.MappedColumnName, StringComparison.OrdinalIgnoreCase)) + if (value == DBNull.Value) { - var value = property.InvokeGet(filterValue) ?? DBNull.Value; - - if (value == DBNull.Value) - { - if (!ignoreNullProperties) - parts[i] = ($"{entry.Details.QuotedSqlName} IS NULL"); - } + if (!ignoreNullProperties) + parts[i] = ($"{entry.Details.QuotedSqlName} IS NULL"); + } + else + { + entry.ParameterValue = value; + if (!useSecondSlot) + entry.UseParameter = true; else - { - entry.ParameterValue = value; - if (!useSecondSlot) - entry.UseParameter = true; - else - entry.UseParameter2 = true; - parts[i] = ($"{entry.Details.QuotedSqlName} = ?"); - } - - found = true; - propertyFound = true; - break; + entry.UseParameter2 = true; + parts[i] = ($"{entry.Details.QuotedSqlName} = ?"); } + + found = true; + propertyFound = true; + break; } - if (StrictMode && !propertyFound) - throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); } + if (StrictMode && !propertyFound) + throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); } + } - if (!found) - throw new MappingException($"None of the properties on {filterValue.GetType().Name} could be matched to columns in {m_Name}."); + if (!found) + throw new MappingException($"None of the properties on {filterValue.GetType().Name} could be matched to columns in {m_Name}."); - return string.Join(" AND ", parts.Where(s => s != null)); - } + return string.Join(" AND ", parts.Where(s => s != null)); + } - /// - /// Applies the argument value for an undefined operation. - /// - /// The data source. - /// The value. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - public void ApplyArgumentValue(IDataSource dataSource, object? argumentValue) - { - ApplyArgumentValue(dataSource, OperationTypes.None, argumentValue, false, false, false); - } + /// + /// Applies the argument value for an undefined operation. + /// + /// The data source. + /// The value. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + public void ApplyArgumentValue(IDataSource dataSource, object? argumentValue) + { + ApplyArgumentValue(dataSource, OperationTypes.None, argumentValue, false, false, false); + } - /// - /// Applies the argument value. - /// - /// The data source. - /// Type of the operation. - /// The value. - /// No result will be read from this operation. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - public void ApplyArgumentValue(IDataSource dataSource, OperationTypes operationType, object? argumentValue, bool nonQueryDelete) - { - ApplyArgumentValue(dataSource, operationType, argumentValue, false, false, nonQueryDelete); - } + /// + /// Applies the argument value. + /// + /// The data source. + /// Type of the operation. + /// The value. + /// No result will be read from this operation. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + public void ApplyArgumentValue(IDataSource dataSource, OperationTypes operationType, object? argumentValue, bool nonQueryDelete) + { + ApplyArgumentValue(dataSource, operationType, argumentValue, false, false, nonQueryDelete); + } - /// - /// Applies the argument value. - /// - /// The data source. - /// The value. - /// The options. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - /// - [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "options")] - public void ApplyArgumentValue(IDataSource dataSource, object argumentValue, InsertOptions options) - { - ApplyArgumentValue(dataSource, OperationTypes.Insert, argumentValue, false, false, false); - } + /// + /// Applies the argument value. + /// + /// The data source. + /// The value. + /// The options. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + /// + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "options")] + public void ApplyArgumentValue(IDataSource dataSource, object argumentValue, InsertOptions options) + { + ApplyArgumentValue(dataSource, OperationTypes.Insert, argumentValue, false, false, false); + } - /// - /// Applies the argument value. - /// - /// The data source. - /// The value. - /// The options. - /// No result will be read from this operation. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - /// - public void ApplyArgumentValue(IDataSource dataSource, object argumentValue, DeleteOptions options, bool nonQuery) - { - ApplyArgumentValue(dataSource, OperationTypes.Delete, argumentValue, options.HasFlag(DeleteOptions.UseKeyAttribute), false, nonQuery); - } + /// + /// Applies the argument value. + /// + /// The data source. + /// The value. + /// The options. + /// No result will be read from this operation. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + /// + public void ApplyArgumentValue(IDataSource dataSource, object argumentValue, DeleteOptions options, bool nonQuery) + { + ApplyArgumentValue(dataSource, OperationTypes.Delete, argumentValue, options.HasFlag(DeleteOptions.UseKeyAttribute), false, nonQuery); + } - /// - /// Applies the argument value. - /// - /// The data source. - /// The value. - /// The options. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - /// If the object does not implement IPropertyChangeTracking, the changedPropertiesOnly flag has no effect. - /// - public void ApplyArgumentValue(IDataSource dataSource, object argumentValue, UpsertOptions options) - { - ApplyArgumentValue(dataSource, OperationTypes.InsertOrUpdate, argumentValue, options.HasFlag(UpsertOptions.UseKeyAttribute), options.HasFlag(UpsertOptions.ChangedPropertiesOnly), false); - } + /// + /// Applies the argument value. + /// + /// The data source. + /// The value. + /// The options. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + /// If the object does not implement IPropertyChangeTracking, the changedPropertiesOnly flag has no effect. + /// + public void ApplyArgumentValue(IDataSource dataSource, object argumentValue, UpsertOptions options) + { + ApplyArgumentValue(dataSource, OperationTypes.InsertOrUpdate, argumentValue, options.HasFlag(UpsertOptions.UseKeyAttribute), options.HasFlag(UpsertOptions.ChangedPropertiesOnly), false); + } - /// - /// Applies the argument value. - /// - /// The data source. - /// The value. - /// The options. - /// No result will be read from this operation. This is ignored unless using UpdateOptions.SoftDelete. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - /// If the object does not implement IPropertyChangeTracking and changedPropertiesOnly is set, an error will occur. - /// - public void ApplyArgumentValue(IDataSource dataSource, object? argumentValue, UpdateOptions options, bool nonQueryDelete) - { - if (options.HasFlag(UpdateOptions.SoftDelete)) - ApplyArgumentValue(dataSource, OperationTypes.Delete, argumentValue, options.HasFlag(UpdateOptions.UseKeyAttribute), options.HasFlag(UpdateOptions.ChangedPropertiesOnly), nonQueryDelete); - else - ApplyArgumentValue(dataSource, OperationTypes.Update, argumentValue, options.HasFlag(UpdateOptions.UseKeyAttribute), options.HasFlag(UpdateOptions.ChangedPropertiesOnly), false); - } + /// + /// Applies the argument value. + /// + /// The data source. + /// The value. + /// The options. + /// No result will be read from this operation. This is ignored unless using UpdateOptions.SoftDelete. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + /// If the object does not implement IPropertyChangeTracking and changedPropertiesOnly is set, an error will occur. + /// + public void ApplyArgumentValue(IDataSource dataSource, object? argumentValue, UpdateOptions options, bool nonQueryDelete) + { + if (options.HasFlag(UpdateOptions.SoftDelete)) + ApplyArgumentValue(dataSource, OperationTypes.Delete, argumentValue, options.HasFlag(UpdateOptions.UseKeyAttribute), options.HasFlag(UpdateOptions.ChangedPropertiesOnly), nonQueryDelete); + else + ApplyArgumentValue(dataSource, OperationTypes.Update, argumentValue, options.HasFlag(UpdateOptions.UseKeyAttribute), options.HasFlag(UpdateOptions.ChangedPropertiesOnly), false); + } - /// - /// Uses a desired columns enumeration to indicate which columns should be set to read-mode. - /// - /// The desired columns. This also supports Materializer.NoColumns, Materializer.AutoSelectDesiredColumns, and Materializer.AllColumns. - /// This is thrown is no desired columns were actually part of the table or view. If strict mode, all desired columns must be found. - /// Calling this a second time will be additive with prior call. - public void ApplyDesiredColumns(IEnumerable desiredColumns) - { - if (desiredColumns == null) - throw new ArgumentNullException(nameof(desiredColumns), $"{nameof(desiredColumns)} is null."); + /// + /// Uses a desired columns enumeration to indicate which columns should be set to read-mode. + /// + /// The desired columns. This also supports Materializer.NoColumns, Materializer.AutoSelectDesiredColumns, and Materializer.AllColumns. + /// This is thrown is no desired columns were actually part of the table or view. If strict mode, all desired columns must be found. + /// Calling this a second time will be additive with prior call. + public void ApplyDesiredColumns(IEnumerable desiredColumns) + { + if (desiredColumns == null) + throw new ArgumentNullException(nameof(desiredColumns), $"{nameof(desiredColumns)} is null."); + + bool found = false; - bool found = false; + if (desiredColumns == Materializer.NoColumns) + return;//no-op, we default m_Entries[i].Read to false - if (desiredColumns == Materializer.NoColumns) - return;//no-op, we default m_Entries[i].Read to false + if (desiredColumns == Materializer.AutoSelectDesiredColumns) + { + //we want primary keys + for (var i = 0; i < m_Entries.Length; i++) + { + ref var entry = ref m_Entries[i]; + if (entry.IsKey) + { + entry.UseForRead = true; + found = true; + } + } + if (found) + return; - if (desiredColumns == Materializer.AutoSelectDesiredColumns) + //we will accept identity columns { - //we want primary keys for (var i = 0; i < m_Entries.Length; i++) { ref var entry = ref m_Entries[i]; - if (entry.IsKey) + if (entry.Details.IsIdentity) { entry.UseForRead = true; found = true; } } - if (found) - return; - - //we will accept identity columns - { - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; - if (entry.Details.IsIdentity) - { - entry.UseForRead = true; - found = true; - } - } - } - if (found) - return; - - //we have nothing - if (!found) - throw new MappingException($"Could not find a primary key for {m_Name}."); } + if (found) + return; - if (desiredColumns == Materializer.AllColumns) - { - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; + //we have nothing + if (!found) + throw new MappingException($"Could not find a primary key for {m_Name}."); + } - if (entry.Details.SqlName != null) - entry.UseForRead = true; - } + if (desiredColumns == Materializer.AllColumns) + { + for (var i = 0; i < m_Entries.Length; i++) + { + ref var entry = ref m_Entries[i]; - return; + if (entry.Details.SqlName != null) + entry.UseForRead = true; } - //This has to go last. THe special case versions of desired columns also have 0 named columns. - if (desiredColumns.Count() == 0) - throw new ChainInternalException("No desired columns were requested."); + return; + } + + //This has to go last. THe special case versions of desired columns also have 0 named columns. + if (desiredColumns.Count() == 0) + throw new ChainInternalException("No desired columns were requested."); + + foreach (var column in desiredColumns) + { + var columnFound = false; - foreach (var column in desiredColumns) + for (var i = 0; i < m_Entries.Length; i++) { - var columnFound = false; + ref var entry = ref m_Entries[i]; - for (var i = 0; i < m_Entries.Length; i++) + if (string.Equals(entry.Details.SqlName, column, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; - - if (string.Equals(entry.Details.SqlName, column, StringComparison.OrdinalIgnoreCase)) - { - entry.UseForRead = true; - columnFound = true; - found = true; - break; - } - else if (string.Equals(entry.Details.ClrName, column, StringComparison.OrdinalIgnoreCase)) - { - entry.UseClrNameAsAlias = true; - entry.UseForRead = true; - columnFound = true; - found = true; - break; - } - else if (string.Equals(entry.Details.QuotedSqlName, column, StringComparison.OrdinalIgnoreCase)) - { - throw new MappingException($"Modify the ColumnAttribute for the desired column \"{column}\" to be \"{entry.Details.SqlName}\". SQL Quoted column names are not supported."); - } + entry.UseForRead = true; + columnFound = true; + found = true; + break; + } + else if (string.Equals(entry.Details.ClrName, column, StringComparison.OrdinalIgnoreCase)) + { + entry.UseClrNameAsAlias = true; + entry.UseForRead = true; + columnFound = true; + found = true; + break; + } + else if (string.Equals(entry.Details.QuotedSqlName, column, StringComparison.OrdinalIgnoreCase)) + { + throw new MappingException($"Modify the ColumnAttribute for the desired column \"{column}\" to be \"{entry.Details.SqlName}\". SQL Quoted column names are not supported."); } - - if (StrictMode && !columnFound) - throw new MappingException($"Strict mode was enabled, but desired column {column} was not found on {m_Name}. Disable strict mode or mark the property as NotMapped."); } - if (!found) - throw new MappingException($"None of the desired columns were found on {m_Name}." - + Environment.NewLine + "\tAvailable columns: " + string.Join(", ", m_Entries.Select(c => c.Details.SqlName)) - + Environment.NewLine + "\tDesired columns: " + string.Join(", ", desiredColumns) - ); + if (StrictMode && !columnFound) + throw new MappingException($"Strict mode was enabled, but desired column {column} was not found on {m_Name}. Disable strict mode or mark the property as NotMapped."); } - /// - /// Applies the filter value, returning a set of expressions suitable for use in a WHERE clause. - /// - /// The filter value. - /// The filter options. - /// System.String. - /// - /// - /// - /// - public string ApplyFilterValue(object filterValue, FilterOptions filterOptions) - { - if (filterValue == null) - throw new ArgumentNullException(nameof(filterValue), $"{nameof(filterValue)} is null."); + if (!found) + throw new MappingException($"None of the desired columns were found on {m_Name}." + + Environment.NewLine + "\tAvailable columns: " + string.Join(", ", m_Entries.Select(c => c.Details.SqlName)) + + Environment.NewLine + "\tDesired columns: " + string.Join(", ", desiredColumns) + ); + } + + /// + /// Applies the filter value, returning a set of expressions suitable for use in a WHERE clause. + /// + /// The filter value. + /// The filter options. + /// System.String. + /// + /// + /// + /// + public string ApplyFilterValue(object filterValue, FilterOptions filterOptions) + { + if (filterValue == null) + throw new ArgumentNullException(nameof(filterValue), $"{nameof(filterValue)} is null."); - var ignoreNullProperties = filterOptions.HasFlag(FilterOptions.IgnoreNullProperties); - var parts = new List(); - bool found = false; + var ignoreNullProperties = filterOptions.HasFlag(FilterOptions.IgnoreNullProperties); + var parts = new List(); + bool found = false; - if (filterValue is IReadOnlyDictionary readOnlyDictionary) + if (filterValue is IReadOnlyDictionary readOnlyDictionary) + { + foreach (var item in readOnlyDictionary) { - foreach (var item in readOnlyDictionary) + var keyFound = false; + for (var i = 0; i < m_Entries.Length; i++) { - var keyFound = false; - for (var i = 0; i < m_Entries.Length; i++) + ref var entry = ref m_Entries[i]; + + if (string.Equals(entry.Details.ClrName, item.Key, StringComparison.OrdinalIgnoreCase) + || string.Equals(entry.Details.SqlName, item.Key, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; + var value = item.Value ?? DBNull.Value; - if (string.Equals(entry.Details.ClrName, item.Key, StringComparison.OrdinalIgnoreCase) - || string.Equals(entry.Details.SqlName, item.Key, StringComparison.OrdinalIgnoreCase)) + if (value == DBNull.Value) { - var value = item.Value ?? DBNull.Value; - - if (value == DBNull.Value) - { - if (!ignoreNullProperties) - parts.Add($"{entry.Details.QuotedSqlName} IS NULL"); - } - else - { - entry.ParameterValue = value; - entry.UseParameter = true; - parts.Add($"{entry.Details.QuotedSqlName} = {entry.Details.SqlVariableName}"); - } - - found = true; - keyFound = true; - break; + if (!ignoreNullProperties) + parts.Add($"{entry.Details.QuotedSqlName} IS NULL"); + } + else + { + entry.ParameterValue = value; + entry.UseParameter = true; + parts.Add($"{entry.Details.QuotedSqlName} = {entry.Details.SqlVariableName}"); } + + found = true; + keyFound = true; + break; } - if (StrictMode && !keyFound) - throw new MappingException($"Strict mode was enabled, but property {item.Key} could be matched to a column in {m_Name}. Disable strict mode or remove the item from the dictionary."); } + if (StrictMode && !keyFound) + throw new MappingException($"Strict mode was enabled, but property {item.Key} could be matched to a column in {m_Name}. Disable strict mode or remove the item from the dictionary."); } - else + } + else + { + foreach (var property in MetadataCache.GetMetadata(filterValue.GetType()).Properties.Where(p => p.MappedColumnName != null && p.CanRead)) { - foreach (var property in MetadataCache.GetMetadata(filterValue.GetType()).Properties.Where(p => p.MappedColumnName != null)) + var propertyFound = false; + for (var i = 0; i < m_Entries.Length; i++) { - var propertyFound = false; - for (var i = 0; i < m_Entries.Length; i++) + ref var entry = ref m_Entries[i]; + + if (entry.Details.ClrName.Equals(property.MappedColumnName, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; + var value = property.InvokeGet(filterValue) ?? DBNull.Value; - if (entry.Details.ClrName.Equals(property.MappedColumnName, StringComparison.OrdinalIgnoreCase)) + if (value == DBNull.Value) { - var value = property.InvokeGet(filterValue) ?? DBNull.Value; - - if (value == DBNull.Value) - { - if (!ignoreNullProperties) - parts.Add($"{entry.Details.QuotedSqlName} IS NULL"); - } - else - { - entry.ParameterValue = value; - entry.UseParameter = true; - parts.Add($"{entry.Details.QuotedSqlName} = {entry.Details.SqlVariableName}"); - } - - found = true; - propertyFound = true; - break; + if (!ignoreNullProperties) + parts.Add($"{entry.Details.QuotedSqlName} IS NULL"); + } + else + { + entry.ParameterValue = value; + entry.UseParameter = true; + parts.Add($"{entry.Details.QuotedSqlName} = {entry.Details.SqlVariableName}"); } + + found = true; + propertyFound = true; + break; } - if (StrictMode && !propertyFound) - throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); } + if (StrictMode && !propertyFound) + throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); } + } - if (!found) - throw new MappingException($"None of the properties on {filterValue.GetType().Name} could be matched to columns in {m_Name}."); + if (!found) + throw new MappingException($"None of the properties on {filterValue.GetType().Name} could be matched to columns in {m_Name}."); - return string.Join(" AND ", parts); - } + return string.Join(" AND ", parts); + } - /// - /// Applies the audit rules for select operations. - /// - /// The data source. - public void ApplyRulesForSelect(IDataSource dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + /// + /// Applies the audit rules for select operations. + /// + /// The data source. + public void ApplyRulesForSelect(IDataSource dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - ApplyRules(dataSource.AuditRules, OperationTypes.Select, null, dataSource.UserValue); - } + ApplyRules(dataSource.AuditRules, OperationTypes.Select, null, dataSource.UserValue); + } - /// - /// Applies a user defined table type as the argument. - /// - /// The data source. - /// Type of the operation. - /// The table type columns. - /// - /// dataSource - /// or - /// tableTypeColumns - /// - /// None of the columns on the indicated user defined type could be matched to columns in {m_Name}. - public void ApplyTableType(IDataSource dataSource, OperationTypes operationType, IEnumerable> tableTypeColumns) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (tableTypeColumns == null) - throw new ArgumentNullException(nameof(tableTypeColumns), $"{nameof(tableTypeColumns)} is null."); + /// + /// Applies a user defined table type as the argument. + /// + /// The data source. + /// Type of the operation. + /// The table type columns. + /// + /// dataSource + /// or + /// tableTypeColumns + /// + /// None of the columns on the indicated user defined type could be matched to columns in {m_Name}. + public void ApplyTableType(IDataSource dataSource, OperationTypes operationType, IEnumerable> tableTypeColumns) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (tableTypeColumns == null) + throw new ArgumentNullException(nameof(tableTypeColumns), $"{nameof(tableTypeColumns)} is null."); - var found = false; + var found = false; - foreach (var column in tableTypeColumns) + foreach (var column in tableTypeColumns) + { + for (var i = 0; i < m_Entries.Length; i++) { - for (var i = 0; i < m_Entries.Length; i++) + ref var entry = ref m_Entries[i]; + if (string.Equals(entry.Details.SqlName, column.SqlName, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; - if (string.Equals(entry.Details.SqlName, column.SqlName, StringComparison.OrdinalIgnoreCase)) - { - found = true; - entry.ParameterColumn = column; - } + found = true; + entry.ParameterColumn = column; } } + } - if (!found) - throw new MappingException($"None of the columns on the indicated user defined type could be matched to columns in {m_Name}."); + if (!found) + throw new MappingException($"None of the columns on the indicated user defined type could be matched to columns in {m_Name}."); - ApplyRules(dataSource.AuditRules, operationType, null, dataSource.UserValue); - } + ApplyRules(dataSource.AuditRules, operationType, null, dataSource.UserValue); + } - /// - /// Builds FROM clause for a function. - /// - /// The SQL. - /// The header. - /// The footer. - public void BuildAnonymousFromFunctionClause(StringBuilder sql, string header, string footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); + /// + /// Builds FROM clause for a function. + /// + /// The SQL. + /// The header. + /// The footer. + public void BuildAnonymousFromFunctionClause(StringBuilder sql, string header, string footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); - sql.Append(header); - sql.Append(string.Join(", ", GetFormalParameters().Select(_ => "?"))); - sql.Append(footer); - } + sql.Append(header); + sql.Append(string.Join(", ", GetFormalParameters().Select(_ => "?"))); + sql.Append(footer); + } - /// - /// Builds a list of assignments suitable for using in the SET clause of UPDATE statement. This does not include the actual SET keyword. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header. Usually not used. - /// An optional prefix for each column name. - /// The optional footer. Usually not used. - public void BuildAnonymousSetClause(StringBuilder sql, string? header, string? prefix, string? footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + /// + /// Builds a list of assignments suitable for using in the SET clause of UPDATE statement. This does not include the actual SET keyword. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header. Usually not used. + /// An optional prefix for each column name. + /// The optional footer. Usually not used. + public void BuildAnonymousSetClause(StringBuilder sql, string? header, string? prefix, string? footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - sql.Append(header); - sql.Append(string.Join(", ", GetUpdateColumns().Select(x => $"{prefix}{x.QuotedSqlName} = ?"))); - sql.Append(footer); - } + sql.Append(header); + sql.Append(string.Join(", ", GetUpdateColumns().Select(x => $"{prefix}{x.QuotedSqlName} = ?"))); + sql.Append(footer); + } - /// - /// Builds the soft delete clause. - /// - /// The SQL. - /// The header. - /// The data source. - /// The footer. - /// - public void BuildAnonymousSoftDeleteClause(StringBuilder sql, string header, IDataSource dataSource, string? footer) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + /// + /// Builds the soft delete clause. + /// + /// The SQL. + /// The header. + /// The data source. + /// The footer. + /// + public void BuildAnonymousSoftDeleteClause(StringBuilder sql, string header, IDataSource dataSource, string? footer) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - var softDeletes = dataSource.AuditRules.SoftDeleteForSelect; + var softDeletes = dataSource.AuditRules.SoftDeleteForSelect; - if (softDeletes.Length == 0) - return; + if (softDeletes.Length == 0) + return; - var applicableColumns = new HashSet>(); + var applicableColumns = new HashSet>(); - for (var i = 0; i < m_Entries.Length; i++) + for (var i = 0; i < m_Entries.Length; i++) + { + foreach (var rule in softDeletes) { - foreach (var rule in softDeletes) - { - ref var entry = ref m_Entries[i]; + ref var entry = ref m_Entries[i]; - if (string.Equals(entry.Details.SqlName, rule.ColumnName, StringComparison.OrdinalIgnoreCase) || entry.Details.ClrName.Equals(rule.ColumnName, StringComparison.OrdinalIgnoreCase)) - { - entry.ParameterValue = rule.DeletedValue; - entry.UseParameter2 = true; - applicableColumns.Add(entry); - } + if (string.Equals(entry.Details.SqlName, rule.ColumnName, StringComparison.OrdinalIgnoreCase) || entry.Details.ClrName.Equals(rule.ColumnName, StringComparison.OrdinalIgnoreCase)) + { + entry.ParameterValue = rule.DeletedValue; + entry.UseParameter2 = true; + applicableColumns.Add(entry); } } - - if (applicableColumns.Count > 0) - { - sql.Append(header); - sql.Append(string.Join(" AND ", applicableColumns.Select(x => x.Details.QuotedSqlName + " <> ?"))); - sql.Append(footer); - } } - /// - /// Builds a list of columns suitable for using in the VALUES clause of INSERT statement. This does not include the actual VALUES keyword. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header. Usually "VALUES (". - /// The optional footer. Usually just ")". - /// Include the identity column. Used when performing an identity insert operation. - public void BuildAnonymousValuesClause(StringBuilder sql, string header, string footer, bool includeIdentityColumn = false) + if (applicableColumns.Count > 0) { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - sql.Append(header); - sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => "?"))); + sql.Append(string.Join(" AND ", applicableColumns.Select(x => x.Details.QuotedSqlName + " <> ?"))); sql.Append(footer); } + } - /// - /// Builds the standard WHERE clause from Key columns. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header Usually "WHERE". - /// The optional footer. Usually not used. - /// if set to true if this is a first pass parameter. - /// sql - sql - public void BuildAnonymousWhereClause(StringBuilder sql, string? header, string? footer, bool firstPassParameter) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + /// + /// Builds a list of columns suitable for using in the VALUES clause of INSERT statement. This does not include the actual VALUES keyword. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header. Usually "VALUES (". + /// The optional footer. Usually just ")". + /// Include the identity column. Used when performing an identity insert operation. + public void BuildAnonymousValuesClause(StringBuilder sql, string header, string footer, bool includeIdentityColumn = false) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - sql.Append(header); - if (firstPassParameter) - sql.Append(string.Join(" AND ", GetKeyColumns().Select(x => x.QuotedSqlName + " = ?"))); - else - sql.Append(string.Join(" AND ", GetKeyColumns2().Select(x => x.QuotedSqlName + " = ?"))); - sql.Append(footer); - } + sql.Append(header); + sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => "?"))); + sql.Append(footer); + } - /// - /// Builds a complete select statement using the keys as a filter. This is mostly used in conjunction with an UPDATE or DELETE operation. - /// - /// The SQL. - /// Name of the table. - /// Optional footer, usually the statement terminator (;). - public void BuildDeleteStatement(StringBuilder sql, string tableName, string? footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); - if (string.IsNullOrEmpty(tableName)) - throw new ArgumentException($"{nameof(tableName)} is null or empty.", nameof(tableName)); + /// + /// Builds the standard WHERE clause from Key columns. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header Usually "WHERE". + /// The optional footer. Usually not used. + /// if set to true if this is a first pass parameter. + /// sql - sql + public void BuildAnonymousWhereClause(StringBuilder sql, string? header, string? footer, bool firstPassParameter) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + + sql.Append(header); + if (firstPassParameter) + sql.Append(string.Join(" AND ", GetKeyColumns().Select(x => x.QuotedSqlName + " = ?"))); + else + sql.Append(string.Join(" AND ", GetKeyColumns2().Select(x => x.QuotedSqlName + " = ?"))); + sql.Append(footer); + } - sql.Append("DELETE FROM ").Append(tableName); - BuildWhereClause(sql, " WHERE ", footer); - } + /// + /// Builds a complete select statement using the keys as a filter. This is mostly used in conjunction with an UPDATE or DELETE operation. + /// + /// The SQL. + /// Name of the table. + /// Optional footer, usually the statement terminator (;). + public void BuildDeleteStatement(StringBuilder sql, string tableName, string? footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); + if (string.IsNullOrEmpty(tableName)) + throw new ArgumentException($"{nameof(tableName)} is null or empty.", nameof(tableName)); - /// - /// Builds FROM clause for a function. - /// - /// The SQL. - /// The header. - /// The footer. - /// Prefix to apply to each parameter name. - public void BuildFromFunctionClause(StringBuilder sql, string header, string footer, string? parameterPrefix = null) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); + sql.Append("DELETE FROM ").Append(tableName); + BuildWhereClause(sql, " WHERE ", footer); + } - sql.Append(header); - sql.Append(string.Join(", ", GetFormalParameters().Select(s => parameterPrefix + s))); - sql.Append(footer); - } + /// + /// Builds FROM clause for a function. + /// + /// The SQL. + /// The header. + /// The footer. + /// Prefix to apply to each parameter name. + public void BuildFromFunctionClause(StringBuilder sql, string header, string footer, string? parameterPrefix = null) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); - /// - /// Builds a list of columns suitable for using in an INSERT statement. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header. e.g. "INSERT tableName (". - /// An optional prefix for each column name. - /// The optional footer. Usually just ")". - /// Include the identity column. Used when performing an identity insert operation. - public void BuildInsertClause(StringBuilder sql, string? header, string? prefix, string? footer, bool includeIdentityColumn = false) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + sql.Append(header); + sql.Append(string.Join(", ", GetFormalParameters().Select(s => parameterPrefix + s))); + sql.Append(footer); + } - sql.Append(header); - sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => prefix + x.QuotedSqlName))); - sql.Append(footer); - } + /// + /// Builds a list of columns suitable for using in an INSERT statement. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header. e.g. "INSERT tableName (". + /// An optional prefix for each column name. + /// The optional footer. Usually just ")". + /// Include the identity column. Used when performing an identity insert operation. + public void BuildInsertClause(StringBuilder sql, string? header, string? prefix, string? footer, bool includeIdentityColumn = false) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - /// - /// Builds a complete insert statement. - /// - /// The SQL. - /// Name of the table. - /// The footer. - /// Include the identity column. Used when performing an identity insert operation. - public void BuildInsertStatement(StringBuilder sql, string tableName, string? footer, bool includeIdentityColumn = false) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); - if (string.IsNullOrEmpty(tableName)) - throw new ArgumentException($"{nameof(tableName)} is null or empty.", nameof(tableName)); + sql.Append(header); + sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => prefix + x.QuotedSqlName))); + sql.Append(footer); + } - BuildInsertClause(sql, "INSERT INTO " + tableName + " (", null, ")", includeIdentityColumn); - BuildValuesClause(sql, " VALUES (", ")", includeIdentityColumn); - sql.Append(footer); - } + /// + /// Builds a complete insert statement. + /// + /// The SQL. + /// Name of the table. + /// The footer. + /// Include the identity column. Used when performing an identity insert operation. + public void BuildInsertStatement(StringBuilder sql, string tableName, string? footer, bool includeIdentityColumn = false) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); + if (string.IsNullOrEmpty(tableName)) + throw new ArgumentException($"{nameof(tableName)} is null or empty.", nameof(tableName)); + + BuildInsertClause(sql, "INSERT INTO " + tableName + " (", null, ")", includeIdentityColumn); + BuildValuesClause(sql, " VALUES (", ")", includeIdentityColumn); + sql.Append(footer); + } - /// - /// Builds an order by clause. - /// - /// The SQL. - /// The header. - /// The sort expressions. - /// The footer. - /// - /// - public void BuildOrderByClause(StringBuilder sql, string? header, IEnumerable sortExpressions, string? footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); + /// + /// Builds an order by clause. + /// + /// The SQL. + /// The header. + /// The sort expressions. + /// The footer. + /// + /// + public void BuildOrderByClause(StringBuilder sql, string? header, IEnumerable sortExpressions, string? footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); - if (sortExpressions?.Any() != true) - return; + if (sortExpressions?.Any() != true) + return; - sql.Append(header); + sql.Append(header); - var isFirst = true; + var isFirst = true; - foreach (var expression in sortExpressions) - { - //this shouldn't happen, but if it does we'll just ignore it. - if (expression.ColumnName == null) - continue; + foreach (var expression in sortExpressions) + { + //this shouldn't happen, but if it does we'll just ignore it. + if (expression.ColumnName == null) + continue; - if (!isFirst) - sql.Append(", "); + if (!isFirst) + sql.Append(", "); - var columnIndex = FindColumnIndexByName(expression.ColumnName); + var columnIndex = FindColumnIndexByName(expression.ColumnName); + if (columnIndex.HasValue) + { + sql.Append(m_Entries[columnIndex.Value].Details.QuotedSqlName! + (expression.Direction == SortDirection.Descending ? " DESC " : null)); + } + else if (expression.ColumnName.EndsWith(" ACS", StringComparison.OrdinalIgnoreCase)) + { + var truncateedName = expression.ColumnName.Substring(0, expression.ColumnName.Length - 4); + columnIndex = FindColumnIndexByName(truncateedName); if (columnIndex.HasValue) - { - sql.Append(m_Entries[columnIndex.Value].Details.QuotedSqlName! + (expression.Direction == SortDirection.Descending ? " DESC " : null)); - } - else if (expression.ColumnName.EndsWith(" ACS", StringComparison.OrdinalIgnoreCase)) - { - var truncateedName = expression.ColumnName.Substring(0, expression.ColumnName.Length - 4); - columnIndex = FindColumnIndexByName(truncateedName); - if (columnIndex.HasValue) - sql.Append(m_Entries[columnIndex.Value].Details.QuotedSqlName!); - else - throw new MappingException($"Cannot find a column on {m_Name} named '{truncateedName}' or '{expression.ColumnName}'"); - } - else if (expression.ColumnName.EndsWith(" DESC", StringComparison.OrdinalIgnoreCase)) - { - var truncateedName = expression.ColumnName.Substring(0, expression.ColumnName.Length - 5); - columnIndex = FindColumnIndexByName(truncateedName); - if (columnIndex.HasValue) - sql.Append(m_Entries[columnIndex.Value].Details.QuotedSqlName! + " DESC "); - else - throw new MappingException($"Cannot find a column on {m_Name} named '{truncateedName}' or '{expression.ColumnName}'"); - } + sql.Append(m_Entries[columnIndex.Value].Details.QuotedSqlName!); else - throw new MappingException($"Cannot find a column on {m_Name} named '{expression.ColumnName}'"); - - isFirst = false; + throw new MappingException($"Cannot find a column on {m_Name} named '{truncateedName}' or '{expression.ColumnName}'"); + } + else if (expression.ColumnName.EndsWith(" DESC", StringComparison.OrdinalIgnoreCase)) + { + var truncateedName = expression.ColumnName.Substring(0, expression.ColumnName.Length - 5); + columnIndex = FindColumnIndexByName(truncateedName); + if (columnIndex.HasValue) + sql.Append(m_Entries[columnIndex.Value].Details.QuotedSqlName! + " DESC "); + else + throw new MappingException($"Cannot find a column on {m_Name} named '{truncateedName}' or '{expression.ColumnName}'"); } + else + throw new MappingException($"Cannot find a column on {m_Name} named '{expression.ColumnName}'"); - sql.Append(footer); + isFirst = false; } - /// - /// Builds a complete select statement using the keys as a filter. This is mostly used in conjunction with an UPDATE or DELETE operation. - /// - /// The SQL. - /// Name of the table. - /// Optional footer, usually the statement terminator (;). - public void BuildSelectByKeyStatement(StringBuilder sql, string tableName, string footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); - if (string.IsNullOrEmpty(tableName)) - throw new ArgumentException($"{nameof(tableName)} is null or empty.", nameof(tableName)); + sql.Append(footer); + } - if (!HasReadFields) - return; + /// + /// Builds a complete select statement using the keys as a filter. This is mostly used in conjunction with an UPDATE or DELETE operation. + /// + /// The SQL. + /// Name of the table. + /// Optional footer, usually the statement terminator (;). + public void BuildSelectByKeyStatement(StringBuilder sql, string tableName, string footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} is null."); + if (string.IsNullOrEmpty(tableName)) + throw new ArgumentException($"{nameof(tableName)} is null or empty.", nameof(tableName)); - BuildSelectClause(sql, "SELECT ", null, " FROM " + tableName); - BuildWhereClause(sql, " WHERE ", footer); - } + if (!HasReadFields) + return; - /// - /// Builds a list of columns suitable for using in a SELECT or OUTPUT statement. - /// - /// The SQL being generated. - /// The optional header (e.g. "SELECT, OUTPUT). - /// An optional prefix for each column name. - /// The optional footer. - /// - /// If no columns are marked for reading, the header and footer won't be emitted. - /// - public void BuildSelectClause(StringBuilder sql, string? header, string? prefix, string? footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + BuildSelectClause(sql, "SELECT ", null, " FROM " + tableName); + BuildWhereClause(sql, " WHERE ", footer); + } - if (!HasReadFields) - return; + /// + /// Builds a list of columns suitable for using in a SELECT or OUTPUT statement. + /// + /// The SQL being generated. + /// The optional header (e.g. "SELECT, OUTPUT). + /// An optional prefix for each column name. + /// The optional footer. + /// + /// If no columns are marked for reading, the header and footer won't be emitted. + /// + public void BuildSelectClause(StringBuilder sql, string? header, string? prefix, string? footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - sql.Append(header); - sql.Append(string.Join(", ", GetSelectColumns().Select(x => prefix + x))); - sql.Append(footer); - } + if (!HasReadFields) + return; - /// - /// Builds a list of columns suitable for using in a SELECT from @TableParameter clause. - /// - /// The SQL being generated. - /// The optional header (e.g. "SELECT, OUTPUT). - /// An optional prefix for each column name. - /// The optional footer. - /// Include the identity column. Used when performing an identity insert operation. - /// - /// If no columns are marked for reading, the header and footer won't be emitted. - /// - public void BuildSelectTvpForInsertClause(StringBuilder sql, string? header, string? prefix, string? footer, bool includeIdentityColumn = false) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + sql.Append(header); + sql.Append(string.Join(", ", GetSelectColumns().Select(x => prefix + x))); + sql.Append(footer); + } + + /// + /// Builds a list of columns suitable for using in a SELECT from @TableParameter clause. + /// + /// The SQL being generated. + /// The optional header (e.g. "SELECT, OUTPUT). + /// An optional prefix for each column name. + /// The optional footer. + /// Include the identity column. Used when performing an identity insert operation. + /// + /// If no columns are marked for reading, the header and footer won't be emitted. + /// + public void BuildSelectTvpForInsertClause(StringBuilder sql, string? header, string? prefix, string? footer, bool includeIdentityColumn = false) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - var parts = new List(); + var parts = new List(); - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; + for (var i = 0; i < m_Entries.Length; i++) + { + ref var entry = ref m_Entries[i]; - if (!entry.RestrictedInsert && (entry.UseForInsert || (includeIdentityColumn && entry.Details.IsIdentity))) + if (!entry.RestrictedInsert && (entry.UseForInsert || (includeIdentityColumn && entry.Details.IsIdentity))) + { + if (entry.ParameterValue != null) { - if (entry.ParameterValue != null) - { - entry.UseParameter = true; - parts.Add(prefix + entry.Details.SqlVariableName); - } - else if (entry.ParameterColumn != null) - { - parts.Add(prefix + entry.ParameterColumn.QuotedSqlName); - } + entry.UseParameter = true; + parts.Add(prefix + entry.Details.SqlVariableName); + } + else if (entry.ParameterColumn != null) + { + parts.Add(prefix + entry.ParameterColumn.QuotedSqlName); } } - - sql.Append(header); - sql.Append(string.Join(", ", parts)); - sql.Append(footer); } - /// - /// Builds a list of assignments suitable for using in the SET clause of UPDATE statement. This does not include the actual SET keyword. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header. Usually not used. - /// An optional prefix for each column name. - /// The optional footer. Usually not used. - public void BuildSetClause(StringBuilder sql, string? header, string? prefix, string? footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + sql.Append(header); + sql.Append(string.Join(", ", parts)); + sql.Append(footer); + } - sql.Append(header); - sql.Append(string.Join(", ", GetUpdateColumns().Select(x => $"{prefix}{x.QuotedSqlName} = {x.SqlVariableName}"))); - sql.Append(footer); - } + /// + /// Builds a list of assignments suitable for using in the SET clause of UPDATE statement. This does not include the actual SET keyword. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header. Usually not used. + /// An optional prefix for each column name. + /// The optional footer. Usually not used. + public void BuildSetClause(StringBuilder sql, string? header, string? prefix, string? footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - /// - /// Builds the soft delete clause. - /// - /// The SQL. - /// The header. - /// The data source. - /// The footer. - /// - public void BuildSoftDeleteClause(StringBuilder sql, string? header, IDataSource dataSource, string? footer) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + sql.Append(header); + sql.Append(string.Join(", ", GetUpdateColumns().Select(x => $"{prefix}{x.QuotedSqlName} = {x.SqlVariableName}"))); + sql.Append(footer); + } - var softDeletes = dataSource.AuditRules.SoftDeleteForSelect; + /// + /// Builds the soft delete clause. + /// + /// The SQL. + /// The header. + /// The data source. + /// The footer. + /// + public void BuildSoftDeleteClause(StringBuilder sql, string? header, IDataSource dataSource, string? footer) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - if (softDeletes.Length == 0) - return; + var softDeletes = dataSource.AuditRules.SoftDeleteForSelect; - var applicableColumns = new HashSet>(); + if (softDeletes.Length == 0) + return; - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; + var applicableColumns = new HashSet>(); - foreach (var rule in softDeletes) - { - if (string.Equals(entry.Details.SqlName, rule.ColumnName, StringComparison.OrdinalIgnoreCase) || entry.Details.ClrName.Equals(rule.ColumnName, StringComparison.OrdinalIgnoreCase)) - { - entry.ParameterValue = rule.DeletedValue; - entry.UseParameter = true; - applicableColumns.Add(entry); - } - } - } + for (var i = 0; i < m_Entries.Length; i++) + { + ref var entry = ref m_Entries[i]; - if (applicableColumns.Count > 0) + foreach (var rule in softDeletes) { - sql.Append(header); - sql.Append(string.Join(" AND ", applicableColumns.Select(x => x.Details.QuotedSqlName + " <> " + x.Details.SqlVariableName))); - sql.Append(footer); + if (string.Equals(entry.Details.SqlName, rule.ColumnName, StringComparison.OrdinalIgnoreCase) || entry.Details.ClrName.Equals(rule.ColumnName, StringComparison.OrdinalIgnoreCase)) + { + entry.ParameterValue = rule.DeletedValue; + entry.UseParameter = true; + applicableColumns.Add(entry); + } } } - /// - /// Builds the complete update statement using primary keys. - /// - /// The SQL. - /// Name of the table. - /// The footer. - public void BuildUpdateByKeyStatement(StringBuilder sql, string tableName, string? footer) + if (applicableColumns.Count > 0) { - BuildSetClause(sql, "UPDATE " + tableName + " SET ", null, null); - BuildWhereClause(sql, " WHERE ", null); + sql.Append(header); + sql.Append(string.Join(" AND ", applicableColumns.Select(x => x.Details.QuotedSqlName + " <> " + x.Details.SqlVariableName))); sql.Append(footer); } + } - /// - /// Builds a list of columns suitable for using in the VALUES clause of INSERT statement. This does not include the actual VALUES keyword. - /// This will add the associated parameters to the parameters collection. - /// - /// The type of the t parameter. - /// The SQL being generated. - /// The optional header. Usually "VALUES (". - /// The optional footer. Usually just ")". - /// Include the identity column. Used when performing an identity insert operation. - /// The parameter suffix. Must be unique for each row. - /// The parameter list to be updated. - /// The parameter builder. - /// - /// sql - /// or - /// value - /// or - /// parameters - /// or - /// parameterBuilder - /// - /// Call OverrideArgumentValue before invoking this method - public void BuildValuesClause(StringBuilder sql, string header, string footer, bool includeIdentityColumn, string parameterSuffix, List parameters, ParameterBuilderCallback parameterBuilder) - where TParameter : DbParameter - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - if (parameters == null) - throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} was null."); - if (parameterBuilder == null) - throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} was null."); + /// + /// Builds the complete update statement using primary keys. + /// + /// The SQL. + /// Name of the table. + /// The footer. + public void BuildUpdateByKeyStatement(StringBuilder sql, string tableName, string? footer) + { + BuildSetClause(sql, "UPDATE " + tableName + " SET ", null, null); + BuildWhereClause(sql, " WHERE ", null); + sql.Append(footer); + } - sql.Append(header); - sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => x.SqlVariableName + parameterSuffix))); - sql.Append(footer); + /// + /// Builds a list of columns suitable for using in the VALUES clause of INSERT statement. This does not include the actual VALUES keyword. + /// This will add the associated parameters to the parameters collection. + /// + /// The type of the t parameter. + /// The SQL being generated. + /// The optional header. Usually "VALUES (". + /// The optional footer. Usually just ")". + /// Include the identity column. Used when performing an identity insert operation. + /// The parameter suffix. Must be unique for each row. + /// The parameter list to be updated. + /// The parameter builder. + /// + /// sql + /// or + /// value + /// or + /// parameters + /// or + /// parameterBuilder + /// + /// Call OverrideArgumentValue before invoking this method + public void BuildValuesClause(StringBuilder sql, string header, string footer, bool includeIdentityColumn, string parameterSuffix, List parameters, ParameterBuilderCallback parameterBuilder) + where TParameter : DbParameter + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + if (parameters == null) + throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} was null."); + if (parameterBuilder == null) + throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} was null."); + + sql.Append(header); + sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => x.SqlVariableName + parameterSuffix))); + sql.Append(footer); + + var temp = GetParameters(parameterBuilder); + foreach (var item in temp) + item.ParameterName += parameterSuffix; + parameters.AddRange(temp); + } - var temp = GetParameters(parameterBuilder); - foreach (var item in temp) - item.ParameterName += parameterSuffix; - parameters.AddRange(temp); - } + /// + /// Builds a list of columns suitable for using in the VALUES clause of INSERT statement. This does not include the actual VALUES keyword. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header. Usually "VALUES (". + /// The optional footer. Usually just ")". + /// Include the identity column. Used when performing an identity insert operation. + public void BuildValuesClause(StringBuilder sql, string header, string footer, bool includeIdentityColumn = false) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - /// - /// Builds a list of columns suitable for using in the VALUES clause of INSERT statement. This does not include the actual VALUES keyword. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header. Usually "VALUES (". - /// The optional footer. Usually just ")". - /// Include the identity column. Used when performing an identity insert operation. - public void BuildValuesClause(StringBuilder sql, string header, string footer, bool includeIdentityColumn = false) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + sql.Append(header); + sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => x.SqlVariableName))); + sql.Append(footer); + } - sql.Append(header); - sql.Append(string.Join(", ", GetInsertColumns(includeIdentityColumn).Select(x => x.SqlVariableName))); - sql.Append(footer); - } + /// + /// Builds the standard WHERE clause from Key columns. + /// This will mark key columns for use in parameter building. + /// + /// The SQL being generated. + /// The optional header Usually "WHERE". + /// The optional footer. Usually not used. + public void BuildWhereClause(StringBuilder sql, string? header, string? footer) + { + if (sql == null) + throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); - /// - /// Builds the standard WHERE clause from Key columns. - /// This will mark key columns for use in parameter building. - /// - /// The SQL being generated. - /// The optional header Usually "WHERE". - /// The optional footer. Usually not used. - public void BuildWhereClause(StringBuilder sql, string? header, string? footer) - { - if (sql == null) - throw new ArgumentNullException(nameof(sql), $"{nameof(sql)} was null."); + sql.Append(header); + sql.Append(string.Join(" AND ", GetKeyColumns().Select(x => x.QuotedSqlName + " = " + x.SqlVariableName))); + sql.Append(footer); + } - sql.Append(header); - sql.Append(string.Join(" AND ", GetKeyColumns().Select(x => x.QuotedSqlName + " = " + x.SqlVariableName))); - sql.Append(footer); - } + /// + /// Gets every column with a ParameterValue. + /// + /// Each pair has the column's QuotedSqlName and SqlVariableName + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetFormalParameters() + { + for (var i = 0; i < m_Entries.Length; i++) + if (m_Entries[i].IsFormalParameter && m_Entries[i].ParameterValue != null) + yield return m_Entries[i].Details.SqlVariableName; + } - /// - /// Gets every column with a ParameterValue. - /// - /// Each pair has the column's QuotedSqlName and SqlVariableName - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetFormalParameters() + /// + /// Gets the insert columns. + /// + /// Include the identity column. Used when performing an identity insert operation. + /// Each pair has the column's QuotedSqlName and SqlVariableName + /// This will mark the returned columns as participating in the parameter generation. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetInsertColumns(bool includeIdentityColumn = false) + { + for (var i = 0; i < m_Entries.Length; i++) { - for (var i = 0; i < m_Entries.Length; i++) - if (m_Entries[i].IsFormalParameter && m_Entries[i].ParameterValue != null) - yield return m_Entries[i].Details.SqlVariableName; + if (!m_Entries[i].RestrictedInsert && (m_Entries[i].UseForInsert || (includeIdentityColumn && m_Entries[i].Details.IsIdentity)) && (m_Entries[i].ParameterValue != null || m_Entries[i].ParameterColumn != null)) + { + m_Entries[i].UseParameter = true; + yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); + } } + } - /// - /// Gets the insert columns. - /// - /// Include the identity column. Used when performing an identity insert operation. - /// Each pair has the column's QuotedSqlName and SqlVariableName - /// This will mark the returned columns as participating in the parameter generation. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetInsertColumns(bool includeIdentityColumn = false) + /// + /// Gets the key columns. + /// + /// Each pair has the column's QuotedSqlName and SqlVariableName + /// This will mark the returned columns as participating in the parameter generation. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetKeyColumns() + { + for (var i = 0; i < m_Entries.Length; i++) { - for (var i = 0; i < m_Entries.Length; i++) + if (m_Entries[i].IsKey) { - if (!m_Entries[i].RestrictedInsert && (m_Entries[i].UseForInsert || (includeIdentityColumn && m_Entries[i].Details.IsIdentity)) && (m_Entries[i].ParameterValue != null || m_Entries[i].ParameterColumn != null)) - { - m_Entries[i].UseParameter = true; - yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); - } + m_Entries[i].UseParameter = true; + yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); } } + } - /// - /// Gets the key columns. - /// - /// Each pair has the column's QuotedSqlName and SqlVariableName - /// This will mark the returned columns as participating in the parameter generation. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetKeyColumns() - { - for (var i = 0; i < m_Entries.Length; i++) + /// + /// Gets the key columns. + /// + /// Each pair has the column's QuotedSqlName and SqlVariableName + /// This will mark the returned columns as participating in the second pass of parameter generation. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetKeyColumns2() + { + for (var i = 0; i < m_Entries.Length; i++) + if (m_Entries[i].IsKey) { - if (m_Entries[i].IsKey) - { - m_Entries[i].UseParameter = true; - yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); - } + m_Entries[i].UseParameter2 = true; + yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); } - } + } - /// - /// Gets the key columns. - /// - /// Each pair has the column's QuotedSqlName and SqlVariableName - /// This will mark the returned columns as participating in the second pass of parameter generation. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetKeyColumns2() - { - for (var i = 0; i < m_Entries.Length; i++) - if (m_Entries[i].IsKey) - { - m_Entries[i].UseParameter2 = true; - yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); - } - } + /// + /// Gets every column with a ParameterValue. + /// + /// Each pair has the column's QuotedSqlName and SqlVariableName + /// This will mark the returned columns as participating in the parameter generation. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetParameterizedColumns() + { + for (var i = 0; i < m_Entries.Length; i++) + if (m_Entries[i].ParameterValue != null) + { + m_Entries[i].UseParameter = true; + yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); + } + } - /// - /// Gets every column with a ParameterValue. - /// - /// Each pair has the column's QuotedSqlName and SqlVariableName - /// This will mark the returned columns as participating in the parameter generation. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetParameterizedColumns() + /// + /// Gets the parameters. + /// + /// The type of the parameter. + /// The parameter builder. This should set the parameter's database specific DbType property. + /// + [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] + public List GetParameters(ParameterBuilderCallback parameterBuilder) + where TParameter : DbParameter + { + if (parameterBuilder == null) + throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); + + var result = new List(); + + //first pass + for (var i = 0; i < m_Entries.Length; i++) { - for (var i = 0; i < m_Entries.Length; i++) - if (m_Entries[i].ParameterValue != null) - { - m_Entries[i].UseParameter = true; - yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); - } + ref var entry = ref m_Entries[i]; + + if ((entry.UseParameter && entry.ParameterValue != null) || entry.IsOutputParameter) + result.Add(parameterBuilder(entry)); } - /// - /// Gets the parameters. - /// - /// The type of the parameter. - /// The parameter builder. This should set the parameter's database specific DbType property. - /// - [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] - public List GetParameters(ParameterBuilderCallback parameterBuilder) - where TParameter : DbParameter + //second pass + for (var i = 0; i < m_Entries.Length; i++) { - if (parameterBuilder == null) - throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); + ref var entry = ref m_Entries[i]; - var result = new List(); + if (entry.UseParameter2 && entry.ParameterValue != null) + result.Add(parameterBuilder(entry)); + } - //first pass - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; + return result; + } - if ((entry.UseParameter && entry.ParameterValue != null) || entry.IsOutputParameter) - result.Add(parameterBuilder(entry)); - } + /// + /// Gets the parameters, but puts the keys last. + /// + /// The type of the parameter. + /// The parameter builder. This should set the parameter's database specific DbType property. + /// + /// This is needed for positional parameters such as MS Access + [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] + public List GetParametersKeysLast(ParameterBuilderCallback parameterBuilder) + where TParameter : DbParameter + { + if (parameterBuilder == null) + throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); - //second pass - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; + var result = new List(); - if (entry.UseParameter2 && entry.ParameterValue != null) - result.Add(parameterBuilder(entry)); - } + //Add non-key values first + for (var i = 0; i < m_Entries.Length; i++) + { + ref var entry = ref m_Entries[i]; - return result; + if (entry.UseParameter && entry.ParameterValue != null && !entry.IsKey) + result.Add(parameterBuilder(entry)); } - /// - /// Gets the parameters, but puts the keys last. - /// - /// The type of the parameter. - /// The parameter builder. This should set the parameter's database specific DbType property. - /// - /// This is needed for positional parameters such as MS Access - [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] - public List GetParametersKeysLast(ParameterBuilderCallback parameterBuilder) - where TParameter : DbParameter + //Now add key values + for (var i = 0; i < m_Entries.Length; i++) { - if (parameterBuilder == null) - throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); + ref var entry = ref m_Entries[i]; - var result = new List(); + if (entry.UseParameter && entry.ParameterValue != null && entry.IsKey) + result.Add(parameterBuilder(entry)); + } - //Add non-key values first - for (var i = 0; i < m_Entries.Length; i++) - { - ref var entry = ref m_Entries[i]; + return result; + } - if (entry.UseParameter && entry.ParameterValue != null && !entry.IsKey) - result.Add(parameterBuilder(entry)); - } + /// + /// Gets the select columns with metadata details. + /// + /// Each entry has the column's metadata + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable> GetSelectColumnDetails() + { + for (var i = 0; i < m_Entries.Length; i++) + if (!m_Entries[i].RestrictedRead && m_Entries[i].UseForRead) + yield return m_Entries[i].Details; + } - //Now add key values - for (var i = 0; i < m_Entries.Length; i++) + /// + /// Gets the select columns. + /// + /// Each entry has the column's QuotedSqlName + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetSelectColumns() + { + for (var i = 0; i < m_Entries.Length; i++) + if (!m_Entries[i].RestrictedRead && m_Entries[i].UseForRead) { - ref var entry = ref m_Entries[i]; + if (!m_Entries[i].UseClrNameAsAlias) + yield return m_Entries[i].Details.QuotedSqlNameSafe(); + else + yield return m_Entries[i].Details.QuotedSqlNameSafe() + " AS " + m_Entries[i].Details.ClrName; + } + } - if (entry.UseParameter && entry.ParameterValue != null && entry.IsKey) - result.Add(parameterBuilder(entry)); + /// + /// Gets the update columns. + /// + /// Each pair has the column's QuotedSqlName and SqlVariableName + /// This will mark the returned columns as participating in the parameter generation. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetUpdateColumns() + { + for (var i = 0; i < m_Entries.Length; i++) + if (!m_Entries[i].RestrictedUpdate && m_Entries[i].UseForUpdate && m_Entries[i].ParameterValue != null) + { + m_Entries[i].UseParameter = true; + yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); } + } - return result; - } + /// + /// Overrides the previous selected values with the values in the indicated object. + /// + /// The data source. + /// The type of operation being performed. + /// The value. + /// value;value is null. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// This will not alter the IsPrimaryKey, Insert, or Update column settings. + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + public void OverrideArgumentValue(IDataSource dataSource, OperationTypes operationType, object? argumentValue) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - /// - /// Gets the select columns with metadata details. - /// - /// Each entry has the column's metadata - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable> GetSelectColumnDetails() - { - for (var i = 0; i < m_Entries.Length; i++) - if (!m_Entries[i].RestrictedRead && m_Entries[i].UseForRead) - yield return m_Entries[i].Details; - } + if (argumentValue == null) + throw new ArgumentNullException(nameof(argumentValue), $"{nameof(argumentValue)} is null."); - /// - /// Gets the select columns. - /// - /// Each entry has the column's QuotedSqlName - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetSelectColumns() + if (argumentValue is IReadOnlyDictionary readOnlyDictionary) { - for (var i = 0; i < m_Entries.Length; i++) - if (!m_Entries[i].RestrictedRead && m_Entries[i].UseForRead) - { - if (!m_Entries[i].UseClrNameAsAlias) - yield return m_Entries[i].Details.QuotedSqlNameSafe(); - else - yield return m_Entries[i].Details.QuotedSqlNameSafe() + " AS " + m_Entries[i].Details.ClrName; - } + ApplyArgumentDictionary(readOnlyDictionary); + return; } - /// - /// Gets the update columns. - /// - /// Each pair has the column's QuotedSqlName and SqlVariableName - /// This will mark the returned columns as participating in the parameter generation. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetUpdateColumns() - { - for (var i = 0; i < m_Entries.Length; i++) - if (!m_Entries[i].RestrictedUpdate && m_Entries[i].UseForUpdate && m_Entries[i].ParameterValue != null) - { - m_Entries[i].UseParameter = true; - yield return new ColumnNamePair(m_Entries[i].Details.QuotedSqlNameSafe(), m_Entries[i].Details.SqlVariableName); - } - } + var found = false; - /// - /// Overrides the previous selected values with the values in the indicated object. - /// - /// The data source. - /// The type of operation being performed. - /// The value. - /// value;value is null. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// This will not alter the IsPrimaryKey, Insert, or Update column settings. - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - public void OverrideArgumentValue(IDataSource dataSource, OperationTypes operationType, object? argumentValue) + var metadata = MetadataCache.GetMetadata(argumentValue.GetType()); + foreach (var property in metadata.Properties) { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - - if (argumentValue == null) - throw new ArgumentNullException(nameof(argumentValue), $"{nameof(argumentValue)} is null."); - - if (argumentValue is IReadOnlyDictionary readOnlyDictionary) - { - ApplyArgumentDictionary(readOnlyDictionary); - return; - } + var propertyFound = false; - var found = false; + if (property.MappedColumnName == null) + continue; - var metadata = MetadataCache.GetMetadata(argumentValue.GetType()); - foreach (var property in metadata.Properties) + for (var i = 0; i < m_Entries.Length; i++) { - var propertyFound = false; - - if (property.MappedColumnName == null) - continue; + ref var entry = ref m_Entries[i]; - for (var i = 0; i < m_Entries.Length; i++) + if (entry.Details.ClrName.Equals(property.MappedColumnName, StringComparison.OrdinalIgnoreCase)) { - ref var entry = ref m_Entries[i]; - - if (entry.Details.ClrName.Equals(property.MappedColumnName, StringComparison.OrdinalIgnoreCase)) - { - found = true; - propertyFound = true; - if (entry.IsFormalParameter) - entry.UseParameter = true; - entry.ParameterValue = property.InvokeGet(argumentValue) ?? DBNull.Value; - break; - } + found = true; + propertyFound = true; + if (entry.IsFormalParameter) + entry.UseParameter = true; + entry.ParameterValue = property.InvokeGet(argumentValue) ?? DBNull.Value; + break; } - if (StrictMode && !propertyFound) - throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); } + if (StrictMode && !propertyFound) + throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); + } - if (!found) - throw new MappingException($"None of the properties on {argumentValue.GetType().Name} could be matched to columns in {m_Name}."); + if (!found) + throw new MappingException($"None of the properties on {argumentValue.GetType().Name} could be matched to columns in {m_Name}."); - ApplyRules(dataSource.AuditRules, operationType, null, dataSource.UserValue); + ApplyRules(dataSource.AuditRules, operationType, null, dataSource.UserValue); + } + + /// + /// Overrides the list of keys. + /// + /// The key columns in SqlName format. The column names should be normalized before calling this method. + public void OverrideKeys(ICollection keyColumns) + { + if (keyColumns == null || keyColumns.Count == 0) + throw new ArgumentException($"{nameof(keyColumns)} is null or empty.", nameof(keyColumns)); + + for (var i = 0; i < m_Entries.Length; i++) + { + ref var entry = ref m_Entries[i]; + entry.IsKey = keyColumns.Contains(entry.Details.SqlName ?? ""); + entry.UseForUpdate = entry.UseForUpdate && !entry.IsKey; //If are using the column as a key, we shouldn't update it } + } + + /// + /// Returns true is the primary key includes an identity column. + /// + /// The type of the parameter. + /// The parameter builder. + /// The key parameters. + /// + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")] + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1")] + public bool PrimaryKeyIsIdentity(Func parameterBuilder, out List keyParameters) + where TParameter : DbParameter + { + if (parameterBuilder == null) + throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); - /// - /// Overrides the list of keys. - /// - /// The key columns in SqlName format. The column names should be normalized before calling this method. - public void OverrideKeys(ICollection keyColumns) + bool primKeyIsIdent = false; + keyParameters = new List(); + for (int i = 0; i < m_Entries.Length; i++) { - if (keyColumns == null || keyColumns.Count == 0) - throw new ArgumentException($"{nameof(keyColumns)} is null or empty.", nameof(keyColumns)); + ref var entry = ref m_Entries[i]; - for (var i = 0; i < m_Entries.Length; i++) + if (entry.IsKey && entry.Details.IsIdentity) { - ref var entry = ref m_Entries[i]; - entry.IsKey = keyColumns.Contains(entry.Details.SqlName ?? ""); - entry.UseForUpdate = entry.UseForUpdate && !entry.IsKey; //If are using the column as a key, we shouldn't update it + primKeyIsIdent = true; + + var item = parameterBuilder(entry.Details.DbType); + item.ParameterName = entry.Details.SqlVariableName; + item.Value = entry.ParameterValue; + keyParameters.Add(item); } } - /// - /// Returns true is the primary key includes an identity column. - /// - /// The type of the parameter. - /// The parameter builder. - /// The key parameters. - /// - [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")] - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1")] - public bool PrimaryKeyIsIdentity(Func parameterBuilder, out List keyParameters) - where TParameter : DbParameter - { - if (parameterBuilder == null) - throw new ArgumentNullException(nameof(parameterBuilder), $"{nameof(parameterBuilder)} is null."); + return primKeyIsIdent; + } + + /// + /// Clones this instance so that you can modify it without affecting the cached original. + /// + /// + internal SqlBuilder Clone(bool strictMode) + { + return new SqlBuilder(m_Name, m_Entries, strictMode); + } + + /// + /// Applies an argument dictionary, overriding any previously applied values. + /// + /// The value. + /// This is thrown is no keys could be matched to a column. If strict mode, all keys must match columns. + void ApplyArgumentDictionary(IReadOnlyDictionary value) + { + if (value == null || value.Count == 0) + throw new ArgumentException($"{nameof(value)} is null or empty.", nameof(value)); + + bool found = false; - bool primKeyIsIdent = false; - keyParameters = new List(); - for (int i = 0; i < m_Entries.Length; i++) + foreach (var item in value) + { + var keyFound = false; + for (var i = 0; i < m_Entries.Length; i++) { ref var entry = ref m_Entries[i]; - if (entry.IsKey && entry.Details.IsIdentity) + if (string.Equals(entry.Details.ClrName, item.Key, StringComparison.OrdinalIgnoreCase) + || string.Equals(entry.Details.SqlName, item.Key, StringComparison.OrdinalIgnoreCase) + || string.Equals(entry.Details.SqlVariableName, item.Key, StringComparison.OrdinalIgnoreCase) + ) { - primKeyIsIdent = true; - - var item = parameterBuilder(entry.Details.DbType); - item.ParameterName = entry.Details.SqlVariableName; - item.Value = entry.ParameterValue; - keyParameters.Add(item); + if (entry.IsFormalParameter) + entry.UseParameter = true; + entry.ParameterValue = item.Value ?? DBNull.Value; + found = true; + keyFound = true; + //break; In the case of TVFs, the same column may appear twice } } - - return primKeyIsIdent; + if (StrictMode && !keyFound) + throw new MappingException($"Strict mode was enabled, but property {item.Key} could be matched to a column in {m_Name}. Disable strict mode or remove the item from the dictionary."); } - /// - /// Clones this instance so that you can modify it without affecting the cached original. - /// - /// - internal SqlBuilder Clone(bool strictMode) + if (!found) + throw new MappingException($"None of the keys could be matched to columns or parameters in {m_Name}."); + } + + /// + /// Applies the argument value. + /// + /// The data source. + /// The operation type. + /// The argument value. + /// if set to true use object defined keys. + /// if set to true filter the update list according to IPropertyChangeTracking.ChangedProperties. + /// No result will be read from this operation. + /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. + /// value;value is null. + /// + /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. + /// If the object does not implement IPropertyChangeTracking and changedPropertiesOnly is set, an error will occur. + /// + void ApplyArgumentValue(IDataSource dataSource, OperationTypes operationType, object? argumentValue, bool useObjectDefinedKeys, bool changedPropertiesOnly, bool nonQueryDelete) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + + if (argumentValue == null) { - return new SqlBuilder(m_Name, m_Entries, strictMode); + //only apply audit rules } - - /// - /// Applies an argument dictionary, overriding any previously applied values. - /// - /// The value. - /// This is thrown is no keys could be matched to a column. If strict mode, all keys must match columns. - void ApplyArgumentDictionary(IReadOnlyDictionary value) + else if (argumentValue is IReadOnlyDictionary readOnlyDictionary) { - if (value == null || value.Count == 0) - throw new ArgumentException($"{nameof(value)} is null or empty.", nameof(value)); - - bool found = false; - - foreach (var item in value) + ApplyArgumentDictionary(readOnlyDictionary); + } + else + { + IReadOnlyList changedProperties = Array.Empty(); + if (changedPropertiesOnly) { - var keyFound = false; - for (var i = 0; i < m_Entries.Length; i++) + if (argumentValue is IPropertyChangeTracking propertyChangeTracking) { - ref var entry = ref m_Entries[i]; - - if (string.Equals(entry.Details.ClrName, item.Key, StringComparison.OrdinalIgnoreCase) - || string.Equals(entry.Details.SqlName, item.Key, StringComparison.OrdinalIgnoreCase) - || string.Equals(entry.Details.SqlVariableName, item.Key, StringComparison.OrdinalIgnoreCase) - ) - { - if (entry.IsFormalParameter) - entry.UseParameter = true; - entry.ParameterValue = item.Value ?? DBNull.Value; - found = true; - keyFound = true; - //break; In the case of TVFs, the same column may appear twice - } + changedProperties = propertyChangeTracking.ChangedProperties(); + if (changedProperties.Count == 0) + throw new ArgumentException($"Changed properties were requested, but no properties were marked as changed."); } - if (StrictMode && !keyFound) - throw new MappingException($"Strict mode was enabled, but property {item.Key} could be matched to a column in {m_Name}. Disable strict mode or remove the item from the dictionary."); + else + throw new ArgumentException($"Changed properties were requested, but {argumentValue.GetType().Name} does not implement IPropertyChangeTracking."); } - if (!found) - throw new MappingException($"None of the keys could be matched to columns or parameters in {m_Name}."); - } + if (useObjectDefinedKeys) + for (var i = 0; i < m_Entries.Length; i++) + m_Entries[i].IsKey = false; - /// - /// Applies the argument value. - /// - /// The data source. - /// The operation type. - /// The argument value. - /// if set to true use object defined keys. - /// if set to true filter the update list according to IPropertyChangeTracking.ChangedProperties. - /// No result will be read from this operation. - /// This is thrown is no properties could be matched to a column. If strict mode, all properties must match columns. - /// value;value is null. - /// - /// If the object implements IReadOnlyDictionary[string, object], ApplyArgumentDictionary will be implicitly called instead. - /// If the object does not implement IPropertyChangeTracking and changedPropertiesOnly is set, an error will occur. - /// - void ApplyArgumentValue(IDataSource dataSource, OperationTypes operationType, object? argumentValue, bool useObjectDefinedKeys, bool changedPropertiesOnly, bool nonQueryDelete) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + var found = false; //Any matching properties were found in m_Entries - if (argumentValue == null) - { - //only apply audit rules - } - else if (argumentValue is IReadOnlyDictionary readOnlyDictionary) - { - ApplyArgumentDictionary(readOnlyDictionary); - } - else + var metadata = MetadataCache.GetMetadata(argumentValue.GetType()); + foreach (var property in metadata.Properties) { - IReadOnlyList changedProperties = Array.Empty(); - if (changedPropertiesOnly) - { - if (argumentValue is IPropertyChangeTracking propertyChangeTracking) - { - changedProperties = propertyChangeTracking.ChangedProperties(); - if (changedProperties.Count == 0) - throw new ArgumentException($"Changed properties were requested, but no properties were marked as changed."); - } - else - throw new ArgumentException($"Changed properties were requested, but {argumentValue.GetType().Name} does not implement IPropertyChangeTracking."); - } + var propertyFound = false; //Property exists at all in m_Entries - if (useObjectDefinedKeys) - for (var i = 0; i < m_Entries.Length; i++) - m_Entries[i].IsKey = false; + var mappedColumnName = property.MappedColumnName; - var found = false; //Any matching properties were found in m_Entries - - var metadata = MetadataCache.GetMetadata(argumentValue.GetType()); - foreach (var property in metadata.Properties) - { - var propertyFound = false; //Property exists at all in m_Entries - - var mappedColumnName = property.MappedColumnName; + //Ignore unmapped columns + if (mappedColumnName == null) + continue; - //Ignore unmapped columns - if (mappedColumnName == null) - continue; + //Ignore properties we can't read. (It's probably a protected property, not meant for data binding.) + if (!property.CanRead) + continue; - //Ignore properties we can't read. (It's probably a protected property, not meant for data binding.) - if (!property.CanRead) - continue; + for (var i = 0; i < m_Entries.Length; i++) + { + var isMatch = false; //property is match for m_Entries[i] + ref var entry = ref m_Entries[i]; - for (var i = 0; i < m_Entries.Length; i++) + if (string.Equals(entry.Details.SqlName, mappedColumnName, StringComparison.OrdinalIgnoreCase)) + isMatch = true; + else if (entry.Details.ClrName.Equals(mappedColumnName, StringComparison.OrdinalIgnoreCase)) { - var isMatch = false; //property is match for m_Entries[i] - ref var entry = ref m_Entries[i]; - - if (string.Equals(entry.Details.SqlName, mappedColumnName, StringComparison.OrdinalIgnoreCase)) - isMatch = true; - else if (entry.Details.ClrName.Equals(mappedColumnName, StringComparison.OrdinalIgnoreCase)) - { - isMatch = true; - entry.UseClrNameAsAlias = true; - } - else if (string.Equals(entry.Details.QuotedSqlName, mappedColumnName, StringComparison.OrdinalIgnoreCase)) - { - throw new MappingException($"Modify the ColumnAttribute for the desired column \"{mappedColumnName}\" to be \"{entry.Details.SqlName}\". SQL Quoted column names are not supported."); - } + isMatch = true; + entry.UseClrNameAsAlias = true; + } + else if (string.Equals(entry.Details.QuotedSqlName, mappedColumnName, StringComparison.OrdinalIgnoreCase)) + { + throw new MappingException($"Modify the ColumnAttribute for the desired column \"{mappedColumnName}\" to be \"{entry.Details.SqlName}\". SQL Quoted column names are not supported."); + } - if (isMatch) - { - propertyFound = true; - found = true; + if (isMatch) + { + propertyFound = true; + found = true; - if (useObjectDefinedKeys && property.IsKey) - entry.IsKey = true; + if (useObjectDefinedKeys && property.IsKey) + entry.IsKey = true; - entry.ParameterValue = property.InvokeGet(argumentValue) ?? DBNull.Value; + entry.ParameterValue = property.InvokeGet(argumentValue) ?? DBNull.Value; - if (property.IgnoreOnInsert) - entry.UseForInsert = false; + if (property.IgnoreOnInsert) + entry.UseForInsert = false; - if (property.IgnoreOnUpdate) - entry.UseForUpdate = false; + if (property.IgnoreOnUpdate) + entry.UseForUpdate = false; - if (changedPropertiesOnly && !changedProperties.Contains(property.Name)) - entry.UseForUpdate = false; + if (changedPropertiesOnly && !changedProperties.Contains(property.Name)) + entry.UseForUpdate = false; - if (entry.IsFormalParameter) - entry.UseParameter = true; + if (entry.IsFormalParameter) + entry.UseParameter = true; - //break; In the case of TVFs, the same column may appear twice - } - } - if (StrictMode && !propertyFound && !nonQueryDelete) - { - //When in strict mode and a property wasn't found, throw an exception. This is to warn about possible data loss. - //Exception: If performing a non-query delete, we don't care about the unmatched properties. - //This can happen when using the TableAndView attribute and some columns are only on the view. - throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); + //break; In the case of TVFs, the same column may appear twice } } - - if (!found) - throw new MappingException($"None of the properties on {argumentValue.GetType().Name} could be matched to columns in {m_Name}."); + if (StrictMode && !propertyFound && !nonQueryDelete) + { + //When in strict mode and a property wasn't found, throw an exception. This is to warn about possible data loss. + //Exception: If performing a non-query delete, we don't care about the unmatched properties. + //This can happen when using the TableAndView attribute and some columns are only on the view. + throw new MappingException($"Strict mode was enabled, but property {property.Name} could be matched to a column in {m_Name}. Disable strict mode or mark the property as NotMapped."); + } } - ApplyRules(dataSource.AuditRules, operationType, argumentValue, dataSource.UserValue); + if (!found) + throw new MappingException($"None of the properties on {argumentValue.GetType().Name} could be matched to columns in {m_Name}."); } - /// - /// Applies the indicated rules. - /// - /// The rules. - /// The type of operation. - /// The argument value. - /// The user value. - void ApplyRules(AuditRuleCollection rules, OperationTypes operationType, object? argumentValue, object? userValue) + ApplyRules(dataSource.AuditRules, operationType, argumentValue, dataSource.UserValue); + } + + /// + /// Applies the indicated rules. + /// + /// The rules. + /// The type of operation. + /// The argument value. + /// The user value. + void ApplyRules(AuditRuleCollection rules, OperationTypes operationType, object? argumentValue, object? userValue) + { + if (argumentValue != null) + rules.CheckValidation(argumentValue); + + for (var i = 0; i < m_Entries.Length; i++) { - if (argumentValue != null) - rules.CheckValidation(argumentValue); + ref var entry = ref m_Entries[i]; - for (var i = 0; i < m_Entries.Length; i++) + foreach (var rule in rules.GetRulesForColumn(entry.Details.SqlName, entry.Details.ClrName, operationType)) { - ref var entry = ref m_Entries[i]; + entry.ParameterValue = rule.GenerateValue(argumentValue, userValue, entry.ParameterValue); + entry.ParameterColumn = null; //replaces the TVP columns - foreach (var rule in rules.GetRulesForColumn(entry.Details.SqlName, entry.Details.ClrName, operationType)) - { - entry.ParameterValue = rule.GenerateValue(argumentValue, userValue, entry.ParameterValue); - entry.ParameterColumn = null; //replaces the TVP columns + if (rule.AppliesWhen.HasFlag(OperationTypes.Insert)) + entry.UseForInsert = true; - if (rule.AppliesWhen.HasFlag(OperationTypes.Insert)) - entry.UseForInsert = true; - - //Update is used for soft deletes - if (rule.AppliesWhen.HasFlag(OperationTypes.Update) || rule.AppliesWhen.HasFlag(OperationTypes.Delete)) - entry.UseForUpdate = true; - } + //Update is used for soft deletes + if (rule.AppliesWhen.HasFlag(OperationTypes.Update) || rule.AppliesWhen.HasFlag(OperationTypes.Delete)) + entry.UseForUpdate = true; + } - foreach (var rule in rules.GetRestrictionsForColumn(m_Name, entry.Details.SqlName, entry.Details.ClrName)) - { - var ignoreRule = rule.ExceptWhen(userValue); - if (ignoreRule) - continue; + foreach (var rule in rules.GetRestrictionsForColumn(m_Name, entry.Details.SqlName, entry.Details.ClrName)) + { + var ignoreRule = rule.ExceptWhen(userValue); + if (ignoreRule) + continue; - if (rule.AppliesWhen.HasFlag(OperationTypes.Insert)) - entry.RestrictedInsert = true; + if (rule.AppliesWhen.HasFlag(OperationTypes.Insert)) + entry.RestrictedInsert = true; - if (rule.AppliesWhen.HasFlag(OperationTypes.Update)) - entry.RestrictedUpdate = true; + if (rule.AppliesWhen.HasFlag(OperationTypes.Update)) + entry.RestrictedUpdate = true; - if (rule.AppliesWhen.HasFlag(OperationTypes.Select)) - entry.RestrictedRead = true; - } + if (rule.AppliesWhen.HasFlag(OperationTypes.Select)) + entry.RestrictedRead = true; } } + } - int? FindColumnIndexByName(string columnName) + int? FindColumnIndexByName(string columnName) + { + for (var i = 0; i < m_Entries.Length; i++) { - for (var i = 0; i < m_Entries.Length; i++) + var details = m_Entries[i].Details; + if (string.Equals(details.SqlName, columnName, StringComparison.OrdinalIgnoreCase) || details.ClrName.Equals(columnName, StringComparison.OrdinalIgnoreCase)) { - var details = m_Entries[i].Details; - if (string.Equals(details.SqlName, columnName, StringComparison.OrdinalIgnoreCase) || details.ClrName.Equals(columnName, StringComparison.OrdinalIgnoreCase)) - { - return i; - } + return i; } - return null; } + return null; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`3.cs index cbba0c7da..6365f17f0 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`3.cs @@ -2,179 +2,178 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for table style command builders such as FromTableOrView and FromTableValueFunction. +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the limit option. +/// +/// +[SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] +public abstract class TableDbCommandBuilder : MultipleRowDbCommandBuilder, ITableDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter + where TLimit : struct //really an enum { /// - /// This is the base class for table style command builders such as FromTableOrView and FromTableValueFunction. - /// - /// The type of the command. - /// The type of the parameter. - /// The type of the limit option. - /// - /// - [SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] - public abstract class TableDbCommandBuilder : MultipleRowDbCommandBuilder, ITableDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - where TLimit : struct //really an enum + /// Initializes a new instance of the class. + /// + /// The data source. + protected TableDbCommandBuilder(ICommandDataSource dataSource) : base(dataSource) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - protected TableDbCommandBuilder(ICommandDataSource dataSource) : base(dataSource) - { - } - - /// - /// Gets the default limit option. - /// - /// - /// The default limit options. - /// - /// For most data sources, this will be LimitOptions.Rows. - protected virtual LimitOptions DefaultLimitOption => LimitOptions.Rows; - - /// - /// Returns the row count using a SELECT Count(*) style query. - /// - /// - public abstract ILink AsCount(); - - /// - /// Returns the row count for a given column. SELECT Count(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT(DISTINCT columnName). - /// - public abstract ILink AsCount(string columnName, bool distinct = false); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - public TableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) - => OnWithFilter(filterValue, filterOptions); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - public TableDbCommandBuilder WithFilter(string whereClause) - => OnWithFilter(whereClause, null); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - public TableDbCommandBuilder WithFilter(string whereClause, object? argumentValue) - => OnWithFilter(whereClause, argumentValue); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause, object? argumentValue) => WithFilter(whereClause, argumentValue); - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// - public TableDbCommandBuilder WithLimits(int? skip, int? take) => OnWithLimits(skip, take, DefaultLimitOption, null); - - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// - public TableDbCommandBuilder WithLimits(int? take) => OnWithLimits(null, take, DefaultLimitOption, null); - - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// The limit options. - /// - public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions) => OnWithLimits(null, take, limitOptions, null); - - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions, int seed) => OnWithLimits(null, take, limitOptions, seed); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int take, LimitOptions limitOptions, int? seed) => OnWithLimits(null, take, limitOptions, seed); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int skip, int take) => OnWithLimits(skip, take, DefaultLimitOption, null); - - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - public TableDbCommandBuilder WithSorting(IEnumerable sortExpressions) - => OnWithSorting(sortExpressions); - - /// - /// Adds sorting to the command builder - /// - /// The sort expressions. - /// - public TableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(IEnumerable sortExpressions) => WithSorting(sortExpressions); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - protected abstract TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - protected abstract TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected abstract TableDbCommandBuilder OnWithLimits(int? skip, int? take, TLimit limitOptions, int? seed); - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected abstract TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed); - - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected abstract TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions); } + + /// + /// Gets the default limit option. + /// + /// + /// The default limit options. + /// + /// For most data sources, this will be LimitOptions.Rows. + protected virtual LimitOptions DefaultLimitOption => LimitOptions.Rows; + + /// + /// Returns the row count using a SELECT Count(*) style query. + /// + /// + public abstract ILink AsCount(); + + /// + /// Returns the row count for a given column. SELECT Count(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT(DISTINCT columnName). + /// + public abstract ILink AsCount(string columnName, bool distinct = false); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + public TableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + => OnWithFilter(filterValue, filterOptions); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + public TableDbCommandBuilder WithFilter(string whereClause) + => OnWithFilter(whereClause, null); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + public TableDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + => OnWithFilter(whereClause, argumentValue); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause, object? argumentValue) => WithFilter(whereClause, argumentValue); + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// + public TableDbCommandBuilder WithLimits(int? skip, int? take) => OnWithLimits(skip, take, DefaultLimitOption, null); + + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// + public TableDbCommandBuilder WithLimits(int? take) => OnWithLimits(null, take, DefaultLimitOption, null); + + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// The limit options. + /// + public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions) => OnWithLimits(null, take, limitOptions, null); + + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions, int seed) => OnWithLimits(null, take, limitOptions, seed); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int take, LimitOptions limitOptions, int? seed) => OnWithLimits(null, take, limitOptions, seed); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int skip, int take) => OnWithLimits(skip, take, DefaultLimitOption, null); + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + public TableDbCommandBuilder WithSorting(IEnumerable sortExpressions) + => OnWithSorting(sortExpressions); + + /// + /// Adds sorting to the command builder + /// + /// The sort expressions. + /// + public TableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(IEnumerable sortExpressions) => WithSorting(sortExpressions); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + protected abstract TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + protected abstract TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected abstract TableDbCommandBuilder OnWithLimits(int? skip, int? take, TLimit limitOptions, int? seed); + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected abstract TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed); + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected abstract TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`4.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`4.cs index 11bffde42..c6a7e984f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`4.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/TableDbCommandBuilder`4.cs @@ -3,253 +3,252 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for table style command builders such as FromTableOrView and FromTableValueFunction. +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the limit option. +/// The type of the object to be constructed. +/// +/// +[SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] +public abstract class TableDbCommandBuilder : TableDbCommandBuilder, ITableDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter + where TLimit : struct //really an enum + where TObject : class { /// - /// This is the base class for table style command builders such as FromTableOrView and FromTableValueFunction. - /// - /// The type of the command. - /// The type of the parameter. - /// The type of the limit option. - /// The type of the object to be constructed. - /// - /// - [SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] - public abstract class TableDbCommandBuilder : TableDbCommandBuilder, ITableDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter - where TLimit : struct //really an enum - where TObject : class + /// Initializes a new instance of the class. + /// + /// The data source. + protected TableDbCommandBuilder(ICommandDataSource dataSource) : base(dataSource) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - protected TableDbCommandBuilder(ICommandDataSource dataSource) : base(dataSource) - { - } - - /// - /// Materializes the result as a list of objects. - /// - /// The collection options. - /// - public IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) - => ToCollection(collectionOptions); - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The key column. - /// The dictionary options. - /// - public IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - => ToDictionary(keyColumn, dictionaryOptions); - - /// - /// Materializes the result as a dictionary of objects. - /// - /// The type of the key. - /// The key function. - /// The dictionary options. - /// - public IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - => ToDictionary(keyFunction, dictionaryOptions); - - /// - /// Materializes the result as an immutable array of objects. - /// - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. - public IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) - => ToImmutableArray(collectionOptions); - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The key function. - /// The dictionary options. - /// - public IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - => ToImmutableDictionary(keyFunction, dictionaryOptions); - - /// - /// Materializes the result as a immutable dictionary of objects. - /// - /// The type of the key. - /// The key column. - /// The dictionary options. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) - where TKey : notnull - => ToImmutableDictionary(keyColumn, dictionaryOptions); - - /// - /// Materializes the result as an immutable list of objects. - /// - /// The collection options. - /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. - /// - /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. - public IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) - => ToImmutableList(collectionOptions); - - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) - => ToObject(rowOptions); - - /// - /// Materializes the result as an instance of the indicated type - /// - /// The row options. - /// - public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) - => ToObjectOrNull(rowOptions); - - /************************************************************************************************/ - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - new public TableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) - => OnWithFilterTyped(filterValue, filterOptions); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - new public TableDbCommandBuilder WithFilter(string whereClause) - => WithFilter(whereClause, null); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - new public TableDbCommandBuilder WithFilter(string whereClause, object? argumentValue) - => OnWithFilterTyped(whereClause, argumentValue); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause, object? argumentValue) => WithFilter(whereClause, argumentValue); - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// - new public TableDbCommandBuilder WithLimits(int? skip, int? take) => OnWithLimitsTyped(skip, take, DefaultLimitOption, null); - - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// - new public TableDbCommandBuilder WithLimits(int? take) => OnWithLimitsTyped(null, take, DefaultLimitOption, null); - - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// The limit options. - /// - new public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions) => OnWithLimitsTyped(null, take, limitOptions, null); - - /// - /// Adds limits to the command builder. - /// - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - new public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions, int seed) => OnWithLimitsTyped(null, take, limitOptions, seed); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int take, LimitOptions limitOptions, int? seed) => OnWithLimitsTyped(null, take, limitOptions, seed); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int skip, int take) => OnWithLimitsTyped(skip, take, DefaultLimitOption, null); - - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - new public TableDbCommandBuilder WithSorting(IEnumerable sortExpressions) => OnWithSortingTyped(sortExpressions); - - /// - /// Adds sorting to the command builder - /// - /// The sort expressions. - /// - new public TableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(IEnumerable sortExpressions) => WithSorting(sortExpressions); - - ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - TableDbCommandBuilder OnWithFilterTyped(string whereClause, object? argumentValue) - => (TableDbCommandBuilder)OnWithFilter(whereClause, argumentValue); - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - TableDbCommandBuilder OnWithFilterTyped(object filterValue, FilterOptions filterOptions = FilterOptions.None) - => (TableDbCommandBuilder)OnWithFilter(filterValue, filterOptions); - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - TableDbCommandBuilder OnWithLimitsTyped(int? skip, int? take, TLimit limitOptions, int? seed) - => (TableDbCommandBuilder)OnWithLimits(skip, take, limitOptions, seed); - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - TableDbCommandBuilder OnWithLimitsTyped(int? skip, int? take, LimitOptions limitOptions, int? seed) - => (TableDbCommandBuilder)OnWithLimits(skip, take, limitOptions, seed); - - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - TableDbCommandBuilder OnWithSortingTyped(IEnumerable sortExpressions) - => (TableDbCommandBuilder)OnWithSorting(sortExpressions); } + + /// + /// Materializes the result as a list of objects. + /// + /// The collection options. + /// + public IConstructibleMaterializer> ToCollection(CollectionOptions collectionOptions = CollectionOptions.None) + => ToCollection(collectionOptions); + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The key column. + /// The dictionary options. + /// + public IConstructibleMaterializer> ToDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + => ToDictionary(keyColumn, dictionaryOptions); + + /// + /// Materializes the result as a dictionary of objects. + /// + /// The type of the key. + /// The key function. + /// The dictionary options. + /// + public IConstructibleMaterializer> ToDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + => ToDictionary(keyFunction, dictionaryOptions); + + /// + /// Materializes the result as an immutable array of objects. + /// + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableArray<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableList if you only intend to read the result. + public IConstructibleMaterializer> ToImmutableArray(CollectionOptions collectionOptions = CollectionOptions.None) + => ToImmutableArray(collectionOptions); + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The key function. + /// The dictionary options. + /// + public IConstructibleMaterializer> ToImmutableDictionary(Func keyFunction, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + => ToImmutableDictionary(keyFunction, dictionaryOptions); + + /// + /// Materializes the result as a immutable dictionary of objects. + /// + /// The type of the key. + /// The key column. + /// The dictionary options. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public IConstructibleMaterializer> ToImmutableDictionary(string keyColumn, DictionaryOptions dictionaryOptions = DictionaryOptions.None) + where TKey : notnull + => ToImmutableDictionary(keyColumn, dictionaryOptions); + + /// + /// Materializes the result as an immutable list of objects. + /// + /// The collection options. + /// Tortuga.Chain.IConstructibleMaterializer<System.Collections.Immutable.ImmutableList<TObject>>. + /// + /// In theory this will offer better performance than ToImmutableArray if you intend to further modify the result. + public IConstructibleMaterializer> ToImmutableList(CollectionOptions collectionOptions = CollectionOptions.None) + => ToImmutableList(collectionOptions); + + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + public IConstructibleMaterializer ToObject(RowOptions rowOptions = RowOptions.None) + => ToObject(rowOptions); + + /// + /// Materializes the result as an instance of the indicated type + /// + /// The row options. + /// + public IConstructibleMaterializer ToObjectOrNull(RowOptions rowOptions = RowOptions.None) + => ToObjectOrNull(rowOptions); + + /************************************************************************************************/ + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + new public TableDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + => OnWithFilterTyped(filterValue, filterOptions); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + new public TableDbCommandBuilder WithFilter(string whereClause) + => WithFilter(whereClause, null); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + new public TableDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + => OnWithFilterTyped(whereClause, argumentValue); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithFilter(string whereClause, object? argumentValue) => WithFilter(whereClause, argumentValue); + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// + new public TableDbCommandBuilder WithLimits(int? skip, int? take) => OnWithLimitsTyped(skip, take, DefaultLimitOption, null); + + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// + new public TableDbCommandBuilder WithLimits(int? take) => OnWithLimitsTyped(null, take, DefaultLimitOption, null); + + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// The limit options. + /// + new public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions) => OnWithLimitsTyped(null, take, limitOptions, null); + + /// + /// Adds limits to the command builder. + /// + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + new public TableDbCommandBuilder WithLimits(int? take, TLimit limitOptions, int seed) => OnWithLimitsTyped(null, take, limitOptions, seed); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int take, LimitOptions limitOptions, int? seed) => OnWithLimitsTyped(null, take, limitOptions, seed); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithLimits(int skip, int take) => OnWithLimitsTyped(skip, take, DefaultLimitOption, null); + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + new public TableDbCommandBuilder WithSorting(IEnumerable sortExpressions) => OnWithSortingTyped(sortExpressions); + + /// + /// Adds sorting to the command builder + /// + /// The sort expressions. + /// + new public TableDbCommandBuilder WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(IEnumerable sortExpressions) => WithSorting(sortExpressions); + + ITableDbCommandBuilder ITableDbCommandBuilder.WithSorting(params SortExpression[] sortExpressions) => WithSorting((IEnumerable)sortExpressions); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + TableDbCommandBuilder OnWithFilterTyped(string whereClause, object? argumentValue) + => (TableDbCommandBuilder)OnWithFilter(whereClause, argumentValue); + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + TableDbCommandBuilder OnWithFilterTyped(object filterValue, FilterOptions filterOptions = FilterOptions.None) + => (TableDbCommandBuilder)OnWithFilter(filterValue, filterOptions); + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + TableDbCommandBuilder OnWithLimitsTyped(int? skip, int? take, TLimit limitOptions, int? seed) + => (TableDbCommandBuilder)OnWithLimits(skip, take, limitOptions, seed); + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + TableDbCommandBuilder OnWithLimitsTyped(int? skip, int? take, LimitOptions limitOptions, int? seed) + => (TableDbCommandBuilder)OnWithLimits(skip, take, limitOptions, seed); + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + TableDbCommandBuilder OnWithSortingTyped(IEnumerable sortExpressions) + => (TableDbCommandBuilder)OnWithSorting(sortExpressions); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/UpdateSetDbCommandBuilder`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/UpdateSetDbCommandBuilder`2.cs index a4faf7b30..ea651550d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/UpdateSetDbCommandBuilder`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommandBuilders/UpdateSetDbCommandBuilder`2.cs @@ -2,69 +2,68 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.CommandBuilders +namespace Tortuga.Chain.CommandBuilders; + +/// +/// This is the base class for command builders that perform set-based update operations. +/// +/// The type of the t command. +/// The type of the t parameter. +/// +/// +[SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] +public abstract class UpdateSetDbCommandBuilder : MultipleRowDbCommandBuilder, IUpdateSetDbCommandBuilder + where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// This is the base class for command builders that perform set-based update operations. - /// - /// The type of the t command. - /// The type of the t parameter. - /// - /// - [SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")] - public abstract class UpdateSetDbCommandBuilder : MultipleRowDbCommandBuilder, IUpdateSetDbCommandBuilder - where TCommand : DbCommand - where TParameter : DbParameter + /// Initializes a new instance of the class. + /// The data source. + protected UpdateSetDbCommandBuilder(ICommandDataSource dataSource) + : base(dataSource) { - /// Initializes a new instance of the class. - /// The data source. - protected UpdateSetDbCommandBuilder(ICommandDataSource dataSource) - : base(dataSource) - { - } + } - /// - /// Applies this command to all rows. - /// - /// - public abstract UpdateSetDbCommandBuilder All(); + /// + /// Applies this command to all rows. + /// + /// + public abstract UpdateSetDbCommandBuilder All(); - MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.All() => All(); + MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.All() => All(); - IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.All() => All(); + IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.All() => All(); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - public abstract UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + public abstract UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - public abstract UpdateSetDbCommandBuilder WithFilter(string whereClause); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + public abstract UpdateSetDbCommandBuilder WithFilter(string whereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - public abstract UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue); + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + public abstract UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue); - IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); + IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); - IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); + IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); - IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause, object argumentValue) => WithFilter(whereClause, argumentValue); + IMultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause, object argumentValue) => WithFilter(whereClause, argumentValue); - MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); + MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(object filterValue, FilterOptions filterOptions) => WithFilter(filterValue, filterOptions); - MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); + MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause) => WithFilter(whereClause); - MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause, object? argumentValue) => WithFilter(whereClause, argumentValue); - } + MultipleRowDbCommandBuilder IUpdateSetDbCommandBuilder.WithFilter(string whereClause, object? argumentValue) => WithFilter(whereClause, argumentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/CommonAppenders.cs b/Tortuga.Chain/Tortuga.Chain.Core/CommonAppenders.cs index 8d7abdade..c2e82cf0a 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/CommonAppenders.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/CommonAppenders.cs @@ -5,327 +5,326 @@ using Tortuga.Chain.Appenders; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class CommonAppenders. +/// +public static class CommonAppenders { /// - /// Class CommonAppenders. + /// Executes the previous link and caches the result. /// - public static class CommonAppenders + /// The previous link. + /// The cache key. + /// Optional cache policy. + public static ICacheLink Cache(this ILink previousLink, string cacheKey, CachePolicy? policy = null) { - /// - /// Executes the previous link and caches the result. - /// - /// The previous link. - /// The cache key. - /// Optional cache policy. - public static ICacheLink Cache(this ILink previousLink, string cacheKey, CachePolicy? policy = null) - { - return new CacheResultAppender(previousLink, cacheKey, policy); - } + return new CacheResultAppender(previousLink, cacheKey, policy); + } - /// - /// Executes the previous link and caches the result. - /// - /// The type of the t result. - /// The previous link. - /// Function to generate cache keys. - /// Optional cache policy. - /// ICacheLink<TResult>. - public static ICacheLink Cache(this ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) - { - return new CacheResultAppender(previousLink, cacheKeyFunction, policy); - } + /// + /// Executes the previous link and caches the result. + /// + /// The type of the t result. + /// The previous link. + /// Function to generate cache keys. + /// Optional cache policy. + /// ICacheLink<TResult>. + public static ICacheLink Cache(this ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) + { + return new CacheResultAppender(previousLink, cacheKeyFunction, policy); + } - /// - /// Caches all items in the result set. - /// - /// The type of the t collection. - /// The type of the t item. - /// The previous link. - /// Function to generate cache keys. - /// Optional cache policy. - /// ILink<TCollection>. - public static ICacheLink CacheAllItems(this ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) - where TCollection : IEnumerable - { - return new CacheAllItemsAppender(previousLink, cacheKeyFunction, policy); - } + /// + /// Caches all items in the result set. + /// + /// The type of the t collection. + /// The type of the t item. + /// The previous link. + /// Function to generate cache keys. + /// Optional cache policy. + /// ILink<TCollection>. + public static ICacheLink CacheAllItems(this ILink previousLink, Func cacheKeyFunction, CachePolicy? policy = null) + where TCollection : IEnumerable + { + return new CacheAllItemsAppender(previousLink, cacheKeyFunction, policy); + } - /// - /// Invalidates the cache. - /// - /// The previous link. - /// The cache key. - public static ILink InvalidateCache(this ILink previousLink, string cacheKey) - { - return new InvalidateCacheAppender(previousLink, cacheKey); - } + /// + /// Invalidates the cache. + /// + /// The previous link. + /// The cache key. + public static ILink InvalidateCache(this ILink previousLink, string cacheKey) + { + return new InvalidateCacheAppender(previousLink, cacheKey); + } - /// - /// Invalidates the cache. - /// - /// The command builder. - /// The cache key. - /// ILink. - public static ILink InvalidateCache(this IDbCommandBuilder commandBuilder, string cacheKey) - { - if (commandBuilder == null) - throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); - return new InvalidateCacheAppender(commandBuilder.AsNonQuery(), cacheKey); - } + /// + /// Invalidates the cache. + /// + /// The command builder. + /// The cache key. + /// ILink. + public static ILink InvalidateCache(this IDbCommandBuilder commandBuilder, string cacheKey) + { + if (commandBuilder == null) + throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); + return new InvalidateCacheAppender(commandBuilder.AsNonQuery(), cacheKey); + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The previous link. - /// The expression used to test of a parent and child match. - /// The expression to get the collection on the parent to add the child to. - /// The join options. - public static ILink> Join(this ILink, List>> previousLink, Func joinExpression, Func> targetCollectionExpression, JoinOptions joinOptions = JoinOptions.None) - { - return new ExpressionJoinAppender(previousLink, joinExpression, targetCollectionExpression, joinOptions); - } + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The previous link. + /// The expression used to test of a parent and child match. + /// The expression to get the collection on the parent to add the child to. + /// The join options. + public static ILink> Join(this ILink, List>> previousLink, Func joinExpression, Func> targetCollectionExpression, JoinOptions joinOptions = JoinOptions.None) + { + return new ExpressionJoinAppender(previousLink, joinExpression, targetCollectionExpression, joinOptions); + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The previous link. - /// The expression used to test of a parent and child match. - /// The name of the collection property on the parent to add the child to. - /// The join options. - public static ILink> Join(this ILink, List>> previousLink, Func joinExpression, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) - { - return new ExpressionJoinAppender(previousLink, joinExpression, targetCollectionName, joinOptions); - } + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The previous link. + /// The expression used to test of a parent and child match. + /// The name of the collection property on the parent to add the child to. + /// The join options. + public static ILink> Join(this ILink, List>> previousLink, Func joinExpression, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) + { + return new ExpressionJoinAppender(previousLink, joinExpression, targetCollectionName, joinOptions); + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The type of the primary/foreign key. - /// The previous link. - /// The expression to get the primary key from the parent object. - /// The expression to get the foreign key from the child object. - /// The expression to get the collection on the parent to add the child to. - /// The join options. - public static ILink> Join(this ILink, List>> previousLink, - Func primaryKeyExpression, - Func foreignKeyExpression, - Func> targetCollectionExpression, - JoinOptions joinOptions = JoinOptions.None) - where TKey : notnull - { - return new KeyJoinAppender(previousLink, primaryKeyExpression, foreignKeyExpression, targetCollectionExpression, joinOptions); - } + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The type of the primary/foreign key. + /// The previous link. + /// The expression to get the primary key from the parent object. + /// The expression to get the foreign key from the child object. + /// The expression to get the collection on the parent to add the child to. + /// The join options. + public static ILink> Join(this ILink, List>> previousLink, + Func primaryKeyExpression, + Func foreignKeyExpression, + Func> targetCollectionExpression, + JoinOptions joinOptions = JoinOptions.None) + where TKey : notnull + { + return new KeyJoinAppender(previousLink, primaryKeyExpression, foreignKeyExpression, targetCollectionExpression, joinOptions); + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The type of the primary/foreign key. - /// The previous link. - /// The expression to get the primary key from the parent object. - /// The expression to get the foreign key from the child object. - /// The name of the collection property on the parent to add the child to. - /// The join options. - public static ILink> Join(this ILink, List>> previousLink, - Func primaryKeyExpression, - Func foreignKeyExpression, - string targetCollectionName, - JoinOptions joinOptions = JoinOptions.None) - where TKey : notnull - { - return new KeyJoinAppender(previousLink, primaryKeyExpression, foreignKeyExpression, targetCollectionName, joinOptions); - } + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The type of the primary/foreign key. + /// The previous link. + /// The expression to get the primary key from the parent object. + /// The expression to get the foreign key from the child object. + /// The name of the collection property on the parent to add the child to. + /// The join options. + public static ILink> Join(this ILink, List>> previousLink, + Func primaryKeyExpression, + Func foreignKeyExpression, + string targetCollectionName, + JoinOptions joinOptions = JoinOptions.None) + where TKey : notnull + { + return new KeyJoinAppender(previousLink, primaryKeyExpression, foreignKeyExpression, targetCollectionName, joinOptions); + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The previous link. - /// The name of the property used to get the primary key from the parent object. - /// The name of the property used to get the foreign key from the child object. - /// The name of the collection property on the parent to add the child to. - /// The join options. - public static ILink> Join(this ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) - { - var keyType = MetadataCache.GetMetadata(typeof(T1)).Properties[primaryKeyName].PropertyType; - var methodType = typeof(CommonAppenders).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Single(m => m.Name == "Join_Helper"); - var genericMethod = methodType.MakeGenericMethod(typeof(T1), typeof(T2), keyType); + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The previous link. + /// The name of the property used to get the primary key from the parent object. + /// The name of the property used to get the foreign key from the child object. + /// The name of the collection property on the parent to add the child to. + /// The join options. + public static ILink> Join(this ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) + { + var keyType = MetadataCache.GetMetadata(typeof(T1)).Properties[primaryKeyName].PropertyType; + var methodType = typeof(CommonAppenders).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Single(m => m.Name == "Join_Helper"); + var genericMethod = methodType.MakeGenericMethod(typeof(T1), typeof(T2), keyType); - return (ILink>)genericMethod.Invoke(null, new object[] { previousLink, primaryKeyName, foreignKeyName, targetCollectionName, joinOptions })!; - } + return (ILink>)genericMethod.Invoke(null, new object[] { previousLink, primaryKeyName, foreignKeyName, targetCollectionName, joinOptions })!; + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The previous link. - /// The name of the property used to get the primary key from the parent object and the foreign key from the child object. - /// The name of the collection property on the parent to add the child to. - /// The join options. - public static ILink> Join(this ILink, List>> previousLink, string keyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) - { - var keyType = MetadataCache.GetMetadata(typeof(T1)).Properties[keyName].PropertyType; - var methodType = typeof(CommonAppenders).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Single(m => m.Name == "Join_Helper"); - var genericMethod = methodType.MakeGenericMethod(typeof(T1), typeof(T2), keyType); + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The previous link. + /// The name of the property used to get the primary key from the parent object and the foreign key from the child object. + /// The name of the collection property on the parent to add the child to. + /// The join options. + public static ILink> Join(this ILink, List>> previousLink, string keyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) + { + var keyType = MetadataCache.GetMetadata(typeof(T1)).Properties[keyName].PropertyType; + var methodType = typeof(CommonAppenders).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Single(m => m.Name == "Join_Helper"); + var genericMethod = methodType.MakeGenericMethod(typeof(T1), typeof(T2), keyType); - return (ILink>)genericMethod.Invoke(null, new object[] { previousLink, keyName, keyName, targetCollectionName, joinOptions })!; - } + return (ILink>)genericMethod.Invoke(null, new object[] { previousLink, keyName, keyName, targetCollectionName, joinOptions })!; + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The type of the primary/foreign key. - /// The previous link. - /// The name of the property used to get the primary key from the parent object. - /// The name of the property used to get the foreign key from the child object. - /// The name of the collection property on the parent to add the child to. - /// The join options. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public static ILink> Join(this ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) - where TKey : notnull - { - return new KeyJoinAppender(previousLink, primaryKeyName, foreignKeyName, targetCollectionName, joinOptions); - } + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The type of the primary/foreign key. + /// The previous link. + /// The name of the property used to get the primary key from the parent object. + /// The name of the property used to get the foreign key from the child object. + /// The name of the collection property on the parent to add the child to. + /// The join options. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public static ILink> Join(this ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) + where TKey : notnull + { + return new KeyJoinAppender(previousLink, primaryKeyName, foreignKeyName, targetCollectionName, joinOptions); + } - /// - /// Joins a set of child objects to their parent objects. - /// - /// The type of the parent object. - /// The type of the child object. - /// The type of the primary/foreign key. - /// The previous link. - /// The name of the property used to get the primary key from the parent object and the foreign key from the child object. - /// The name of the collection property on the parent to add the child to. - /// The join options. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public static ILink> Join(this ILink, List>> previousLink, string keyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) - where TKey : notnull - { - if (string.IsNullOrEmpty(keyName)) - throw new ArgumentException("keyName is null or empty.", nameof(keyName)); - //other parameters are checked by the constructor. + /// + /// Joins a set of child objects to their parent objects. + /// + /// The type of the parent object. + /// The type of the child object. + /// The type of the primary/foreign key. + /// The previous link. + /// The name of the property used to get the primary key from the parent object and the foreign key from the child object. + /// The name of the collection property on the parent to add the child to. + /// The join options. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public static ILink> Join(this ILink, List>> previousLink, string keyName, string targetCollectionName, JoinOptions joinOptions = JoinOptions.None) + where TKey : notnull + { + if (string.IsNullOrEmpty(keyName)) + throw new ArgumentException("keyName is null or empty.", nameof(keyName)); + //other parameters are checked by the constructor. - return new KeyJoinAppender(previousLink, keyName, keyName, targetCollectionName, joinOptions); - } + return new KeyJoinAppender(previousLink, keyName, keyName, targetCollectionName, joinOptions); + } - /// - /// Ensures that a null will never be returned. - /// - /// The previous link. - /// If the previous link returns a null, an exception is thrown instead. - public static ILink NeverNull(this ILink previousLink) where TResult : class - { - return new NonNullLink(previousLink); - } + /// + /// Ensures that a null will never be returned. + /// + /// The previous link. + /// If the previous link returns a null, an exception is thrown instead. + public static ILink NeverNull(this ILink previousLink) where TResult : class + { + return new NonNullLink(previousLink); + } - /// - /// Ensures that a null will never be returned. - /// - /// The previous link. - /// If the previous link returns a null, an exception is thrown instead. - public static ILink NeverNull(this ILink previousLink) where TResult : struct - { - return new ValueNonNullLink(previousLink); - } + /// + /// Ensures that a null will never be returned. + /// + /// The previous link. + /// If the previous link returns a null, an exception is thrown instead. + public static ILink NeverNull(this ILink previousLink) where TResult : struct + { + return new ValueNonNullLink(previousLink); + } - /// - /// Reads the cache. If the value isn't found, the execute the previous link and cache the result. - /// - /// The previous link. - /// The cache key. - /// Optional cache policy. - public static ILink ReadOrCache(this ILink previousLink, string cacheKey, CachePolicy? policy = null) - { - return new ReadOrCacheResultAppender(previousLink, cacheKey, policy); - } + /// + /// Reads the cache. If the value isn't found, the execute the previous link and cache the result. + /// + /// The previous link. + /// The cache key. + /// Optional cache policy. + public static ILink ReadOrCache(this ILink previousLink, string cacheKey, CachePolicy? policy = null) + { + return new ReadOrCacheResultAppender(previousLink, cacheKey, policy); + } - /// - /// Sets the strict mode, overriding the value set in the DataSource. - /// - /// The previous link. - /// if set to true [strict mode]. - /// - public static ILink SetStrictMode(this ILink previousLink, bool strictMode) - { - return new StrictModeAppender(previousLink, strictMode); - } + /// + /// Sets the sequential access mode, overriding the value set in the DataSource. + /// + /// The previous link. + /// if set to true enable sequential access. + /// + public static ILink SetSequentialAccessMode(this ILink previousLink, bool sequentialAccessMode) + { + return new SequentialAccessModeAppender(previousLink, sequentialAccessMode); + } - /// - /// Sets the sequential access mode, overriding the value set in the DataSource. - /// - /// The previous link. - /// if set to true enable sequential access. - /// - public static ILink SetSequentialAccessMode(this ILink previousLink, bool sequentialAccessMode) - { - return new SequentialAccessModeAppender(previousLink, sequentialAccessMode); - } + /// + /// Sets the strict mode, overriding the value set in the DataSource. + /// + /// The previous link. + /// if set to true [strict mode]. + /// + public static ILink SetStrictMode(this ILink previousLink, bool strictMode) + { + return new StrictModeAppender(previousLink, strictMode); + } - /// - /// Sets the command timeout, overriding the value set in the DataSource. - /// - /// The type of the t result. - /// The previous link. - /// The timeout. - /// ILink<TResult>. - public static ILink SetTimeout(this ILink previousLink, TimeSpan timeout) - { - return new TimeoutAppender(previousLink, timeout); - } + /// + /// Sets the command timeout, overriding the value set in the DataSource. + /// + /// The type of the t result. + /// The previous link. + /// The timeout. + /// ILink<TResult>. + public static ILink SetTimeout(this ILink previousLink, TimeSpan timeout) + { + return new TimeoutAppender(previousLink, timeout); + } - /// - /// Adds DB Command tracing. Information is send to the Debug stream. - /// - /// The previous link. - /// The stream. - /// ILink<TResult>. - public static ILink WithTracing(this ILink previousLink, TextWriter stream) - { - return new TraceAppender(previousLink, stream); - } + /// + /// Performs a transformation on a result. + /// + public static ILink Transform(this ILink previousLink, Func transformation) + { + return new TransformLink(previousLink, transformation); + } - /// - /// Adds DB Command tracing. Information is send to the Debug stream. - /// - /// The previous link. - public static ILink WithTracingToConsole(this ILink previousLink) - { - return new TraceAppender(previousLink, Console.Out); - } + /// + /// Adds DB Command tracing. Information is send to the Debug stream. + /// + /// The previous link. + /// The stream. + /// ILink<TResult>. + public static ILink WithTracing(this ILink previousLink, TextWriter stream) + { + return new TraceAppender(previousLink, stream); + } - /// - /// Adds DB Command tracing. Information is send to the Debug stream. - /// - /// The previous link. - public static ILink WithTracingToDebug(this ILink previousLink) - { - return new TraceAppender(previousLink); - } + /// + /// Adds DB Command tracing. Information is send to the Debug stream. + /// + /// The previous link. + public static ILink WithTracingToConsole(this ILink previousLink) + { + return new TraceAppender(previousLink, Console.Out); + } - internal static ILink> Join_Helper(ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions) - where TKey : notnull - { - return new KeyJoinAppender(previousLink, primaryKeyName, foreignKeyName, targetCollectionName, joinOptions); - } + /// + /// Adds DB Command tracing. Information is send to the Debug stream. + /// + /// The previous link. + public static ILink WithTracingToDebug(this ILink previousLink) + { + return new TraceAppender(previousLink); + } - /// - /// Performs a transformation on a result. - /// - public static ILink Transform(this ILink previousLink, Func transformation) - { - return new TransformLink(previousLink, transformation); - } + internal static ILink> Join_Helper(ILink, List>> previousLink, string primaryKeyName, string foreignKeyName, string targetCollectionName, JoinOptions joinOptions) + where TKey : notnull + { + return new KeyJoinAppender(previousLink, primaryKeyName, foreignKeyName, targetCollectionName, joinOptions); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/CacheReadResult.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/CacheReadResult.cs index b32252e65..1026a55dc 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/CacheReadResult.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/CacheReadResult.cs @@ -1,35 +1,34 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// Lightweight alternative to a Tuple for reading from the cache asynchronously. +/// +/// +[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] +public struct CacheReadResult { /// - /// Lightweight alternative to a Tuple for reading from the cache asynchronously. + /// Initializes a new instance of the struct. /// - /// - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] - public struct CacheReadResult + /// if set to true [key found]. + /// The value. + public CacheReadResult(bool keyFound, T value) { - /// - /// Initializes a new instance of the struct. - /// - /// if set to true [key found]. - /// The value. - public CacheReadResult(bool keyFound, T value) - { - KeyFound = keyFound; - Value = value; - } + KeyFound = keyFound; + Value = value; + } - /// - /// Gets a value indicating whether the key was found. - /// - public bool KeyFound { get; } + /// + /// Gets a value indicating whether the key was found. + /// + public bool KeyFound { get; } - /// - /// Gets the value. - /// - /// The value. - /// Will be Default(T) is the key wasn't found. - public T Value { get; } - } + /// + /// Gets the value. + /// + /// The value. + /// Will be Default(T) is the key wasn't found. + public T Value { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandBuiltEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandBuiltEventArgs.cs index 97b3c31cf..d63cde7d6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandBuiltEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandBuiltEventArgs.cs @@ -1,24 +1,23 @@ using System.Data.Common; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// Class CommandBuiltEventArgs. +/// +public class CommandBuiltEventArgs : EventArgs { /// - /// Class CommandBuiltEventArgs. + /// Initializes a new instance of the class. /// - public class CommandBuiltEventArgs : EventArgs + /// The command. + public CommandBuiltEventArgs(DbCommand command) { - /// - /// Initializes a new instance of the class. - /// - /// The command. - public CommandBuiltEventArgs(DbCommand command) - { - Command = command; - } - - /// - /// Gets the command that was just built. - /// - public DbCommand Command { get; } + Command = command; } + + /// + /// Gets the command that was just built. + /// + public DbCommand Command { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutedEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutedEventArgs.cs index 46af4a93f..7cdd55901 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutedEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutedEventArgs.cs @@ -1,33 +1,32 @@ using System.Data.Common; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// Class CommandExecutedEventArgs is fired . +/// +/// +public class CommandExecutedEventArgs : EventArgs { /// - /// Class CommandExecutedEventArgs is fired . + /// Initializes a new instance of the class. /// - /// - public class CommandExecutedEventArgs : EventArgs + /// The command. + /// The number of rows affected. + public CommandExecutedEventArgs(DbCommand command, int? rowsAffected) { - /// - /// Initializes a new instance of the class. - /// - /// The command. - /// The number of rows affected. - public CommandExecutedEventArgs(DbCommand command, int? rowsAffected) - { - Command = command; - RowsAffected = rowsAffected; - } + Command = command; + RowsAffected = rowsAffected; + } - /// - /// Gets the command that was just built. - /// - public DbCommand Command { get; } + /// + /// Gets the command that was just built. + /// + public DbCommand Command { get; } - /// - /// Gets the number of rows affected, if known. - /// - /// The rows affected. - public int? RowsAffected { get; } - } + /// + /// Gets the number of rows affected, if known. + /// + /// The rows affected. + public int? RowsAffected { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutionToken`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutionToken`2.cs index 327a8c5f4..15a007f02 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutionToken`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandExecutionToken`2.cs @@ -1,77 +1,99 @@ using System.Data.Common; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// This class represents the actual preparation and execution of a command. +/// +/// The type of the command used. +/// The type of the t parameter type. +/// +public class CommandExecutionToken : ExecutionToken + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ICommandDataSource m_DataSource; + /// - /// This class represents the actual preparation and execution of a command. + /// Initializes a new instance of the class. /// - /// The type of the command used. - /// The type of the t parameter type. - /// - public class CommandExecutionToken : ExecutionToken - where TCommand : DbCommand - where TParameter : DbParameter + /// The data source. + /// Name of the operation. This is used for logging. + /// The SQL to be executed. + /// The parameters. + /// Type of the command. + public CommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) + : base(dataSource, operationName, commandText, commandType) { - readonly ICommandDataSource m_DataSource; + m_DataSource = dataSource; + Parameters = parameters; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. This is used for logging. - /// The SQL to be executed. - /// The parameters. - /// Type of the command. - public CommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) - : base(dataSource, operationName, commandText, commandType) - { - m_DataSource = dataSource; - Parameters = parameters; - } + /// + /// Returns True if any parameter is marked as Output or InputOutput + /// + public bool HasOutputParameters => Parameters.Any(x => x.Direction is ParameterDirection.Output or ParameterDirection.InputOutput); - /// - /// Gets the parameters. - /// - /// The parameters. - public IReadOnlyList Parameters { get; } + /// + /// Gets the parameters. + /// + /// The parameters. + public IReadOnlyList Parameters { get; } - /// - /// Applies the command overrides by calling OnBuildCommand, then firing the CommandBuilt event. - /// - /// The command. - public virtual void ApplyCommandOverrides(TCommand command) - { - OnBuildCommand(command); - RaiseCommandBuild(command); - } + /// + /// Applies the command overrides by calling OnBuildCommand, then firing the CommandBuilt event. + /// + /// The command. + public void ApplyCommandOverrides(TCommand command) + { + OnBuildCommand(command); + RaiseCommandBuild(command); + } + + /// + /// Executes the specified implementation. + /// + /// The implementation. + /// The state. + public int? Execute(CommandImplementation implementation, object? state) + { + return m_DataSource.Execute(this, implementation, state); + } - /// - /// Executes the specified implementation. - /// - /// The implementation. - /// The state. - public int? Execute(CommandImplementation implementation, object? state) - { - return m_DataSource.Execute(this, implementation, state); - } + /// + /// Executes the specified implementation asynchronously. + /// + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + public Task ExecuteAsync(CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + return m_DataSource.ExecuteAsync(this, implementation, cancellationToken, state); + } - /// - /// Executes the specified implementation asynchronously. - /// - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - public Task ExecuteAsync(CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - return m_DataSource.ExecuteAsync(this, implementation, cancellationToken, state); - } + /// + /// Populates a DbCommand with the values in the execution token. Then calls OnBuildCommand/RaiseCommandBuild for any custom behavior. + /// + /// The command object to be populated. + /// An optional command timeout. + public void PopulateCommand(TCommand command, TimeSpan? timeout) + { + if (timeout.HasValue) + command.CommandTimeout = (int)timeout.Value.TotalSeconds; + command.CommandText = CommandText; + command.CommandType = CommandType; + foreach (var param in Parameters) + command.Parameters.Add(param); - /// - /// Subclasses can override this method to change the command object after the command text and parameters are loaded. - /// - /// The command. - protected virtual void OnBuildCommand(TCommand command) { } + OnBuildCommand(command); + RaiseCommandBuild(command); } -} + + /// + /// Subclasses can override this method to change the command object after the command text and parameters are loaded. + /// + /// The command. + protected virtual void OnBuildCommand(TCommand command) { } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementation.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementation.cs index 0f61846ad..e22cdecee 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementation.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementation.cs @@ -1,14 +1,13 @@ using System.Data.Common; -namespace Tortuga.Chain.Core -{ - /// - /// The implementation of an operation from a CommandBuilder. - /// - /// The type of the t command. - /// The command. - /// System.Nullable<System.Int32>. - public delegate int? CommandImplementation(TCommand command) - where TCommand : DbCommand +namespace Tortuga.Chain.Core; + +/// +/// The implementation of an operation from a CommandBuilder. +/// +/// The type of the t command. +/// The command. +/// System.Nullable<System.Int32>. +public delegate int? CommandImplementation(TCommand command) + where TCommand : DbCommand ; -} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementationAsync.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementationAsync.cs index 230f6c66e..7655ccb09 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementationAsync.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/CommandImplementationAsync.cs @@ -1,13 +1,12 @@ using System.Data.Common; -namespace Tortuga.Chain.Core -{ - /// - /// The implementation of an operation from a CommandBuilder. - /// - /// The type of the t command. - /// The command. - /// Task<System.Nullable<System.Int32>>. - public delegate Task CommandImplementationAsync(TCommand command) - where TCommand : DbCommand; -} +namespace Tortuga.Chain.Core; + +/// +/// The implementation of an operation from a CommandBuilder. +/// +/// The type of the t command. +/// The command. +/// Task<System.Nullable<System.Int32>>. +public delegate Task CommandImplementationAsync(TCommand command) + where TCommand : DbCommand; diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionToken.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionToken.cs index 87bf624b5..7902e33ed 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionToken.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionToken.cs @@ -1,84 +1,83 @@ using System.Data.Common; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// This class represents the actual preparation and execution of a command. +/// + +public abstract class ExecutionToken { /// - /// This class represents the actual preparation and execution of a command. + /// Initializes a new instance of the class. /// - - public abstract class ExecutionToken + /// The data source. + /// Name of the operation. + /// The command text. + /// Type of the command. + protected ExecutionToken(IDataSource dataSource, string operationName, string? commandText, CommandType commandType) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. - /// The command text. - /// Type of the command. - protected ExecutionToken(IDataSource dataSource, string operationName, string? commandText, CommandType commandType) - { - DataSource = dataSource; - OperationName = operationName; - CommandText = commandText; - CommandType = commandType; - } + DataSource = dataSource; + OperationName = operationName; + CommandText = commandText; + CommandType = commandType; + } - /// - /// Occurs when a command has been built. - /// - /// This is mostly used by appenders to override command behavior. - public event EventHandler? CommandBuilt; + /// + /// Occurs when a command has been built. + /// + /// This is mostly used by appenders to override command behavior. + public event EventHandler? CommandBuilt; - /// - /// Occurs when a command has been built. - /// - /// This is mostly used by appenders to override command behavior. - public event EventHandler? CommandExecuted; + /// + /// Occurs when a command has been built. + /// + /// This is mostly used by appenders to override command behavior. + public event EventHandler? CommandExecuted; - /// - /// Gets a value indicating whether this instance has command executed event. - /// - /// true if this instance has command executed event; otherwise, false. - public bool HasCommandExecutedEvent => CommandExecuted != null; + /// + /// Gets the command text, which is usually SQL. + /// + /// The command text. + public string? CommandText { get; } - /// - /// Gets the command text, which is usually SQL. - /// - /// The command text. - public string? CommandText { get; } + /// + /// Gets the type of the command. + /// + /// The type of the command. + public CommandType CommandType { get; } - /// - /// Gets the type of the command. - /// - /// The type of the command. - public CommandType CommandType { get; } + /// + /// Gets the data source. + /// + /// The data source. + public IDataSource DataSource { get; } - /// - /// Gets the data source. - /// - /// The data source. - public IDataSource DataSource { get; } + /// + /// Gets a value indicating whether this instance has command executed event. + /// + /// true if this instance has command executed event; otherwise, false. + public bool HasCommandExecutedEvent => CommandExecuted != null; - /// - /// Gets the name of the operation being performed. - /// - public string OperationName { get; } + /// + /// Gets the name of the operation being performed. + /// + public string OperationName { get; } - /// - /// Raises the command executed event. - /// - /// The command. - /// The rows affected. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")] - public void RaiseCommandExecuted(DbCommand command, int? rowsAffected) - { - CommandExecuted?.Invoke(this, new CommandExecutedEventArgs(command, rowsAffected)); - } + /// + /// Raises the command executed event. + /// + /// The command. + /// The rows affected. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")] + public void RaiseCommandExecuted(DbCommand command, int? rowsAffected) + { + CommandExecuted?.Invoke(this, new CommandExecutedEventArgs(command, rowsAffected)); + } - internal void RaiseCommandBuild(DbCommand command) - { - CommandBuilt?.Invoke(this, new CommandBuiltEventArgs(command)); - } + internal void RaiseCommandBuild(DbCommand command) + { + CommandBuilt?.Invoke(this, new CommandBuiltEventArgs(command)); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparedEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparedEventArgs.cs index 811d4e4e7..52ff567bd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparedEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparedEventArgs.cs @@ -1,24 +1,23 @@ -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// This occurs just after an execution token is prepared. +/// +/// +public class ExecutionTokenPreparedEventArgs : EventArgs { /// - /// This occurs just after an execution token is prepared. + /// Initializes a new instance of the class. /// - /// - public class ExecutionTokenPreparedEventArgs : EventArgs + /// The execution token. + public ExecutionTokenPreparedEventArgs(ExecutionToken executionToken) { - /// - /// Initializes a new instance of the class. - /// - /// The execution token. - public ExecutionTokenPreparedEventArgs(ExecutionToken executionToken) - { - ExecutionToken = executionToken; - } - - /// - /// Gets the execution token. - /// - /// The execution token. - public ExecutionToken ExecutionToken { get; } + ExecutionToken = executionToken; } + + /// + /// Gets the execution token. + /// + /// The execution token. + public ExecutionToken ExecutionToken { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparingEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparingEventArgs.cs index 6962a21ea..175e10b85 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparingEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/ExecutionTokenPreparingEventArgs.cs @@ -1,28 +1,27 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// This occurs just before an execution token is prepared. +/// +/// +public class ExecutionTokenPreparingEventArgs : EventArgs { /// - /// This occurs just before an execution token is prepared. + /// Initializes a new instance of the class. /// - /// - public class ExecutionTokenPreparingEventArgs : EventArgs + /// The command builder. + public ExecutionTokenPreparingEventArgs(DbCommandBuilder commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - public ExecutionTokenPreparingEventArgs(DbCommandBuilder commandBuilder) - { - CommandBuilder = commandBuilder; - } - - /// - /// Gets the command builder being used to generate the execution token. - /// - /// - /// The command builder. - /// - public DbCommandBuilder CommandBuilder { get; } + CommandBuilder = commandBuilder; } + + /// + /// Gets the command builder being used to generate the execution token. + /// + /// + /// The command builder. + /// + public DbCommandBuilder CommandBuilder { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/ICacheAdapter.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/ICacheAdapter.cs index 80ead1e5e..34fb0d21e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/ICacheAdapter.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/ICacheAdapter.cs @@ -1,68 +1,67 @@ -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// Generic caching adapter. +/// +public interface ICacheAdapter { /// - /// Generic caching adapter. + /// Clears the cache. /// - public interface ICacheAdapter - { - /// - /// Clears the cache. - /// - void Clear(); + void Clear(); - /// - /// Clears the cache asynchronously. - /// - /// Task. - Task ClearAsync(); + /// + /// Clears the cache asynchronously. + /// + /// Task. + Task ClearAsync(); - /// - /// Invalidates the cache. - /// - /// The cache key. - void Invalidate(string cacheKey); + /// + /// Invalidates the cache. + /// + /// The cache key. + void Invalidate(string cacheKey); - /// - /// Invalidates the cache asynchronously. - /// - /// The cache key. - /// Task. - Task InvalidateAsync(string cacheKey); + /// + /// Invalidates the cache asynchronously. + /// + /// The cache key. + /// Task. + Task InvalidateAsync(string cacheKey); - /// - /// Tries the read from cache. - /// - /// - /// The cache key. - /// The result. - /// true if XXXX, false otherwise. - bool TryRead(string cacheKey, out T result); + /// + /// Tries the read from cache. + /// + /// + /// The cache key. + /// The result. + /// true if XXXX, false otherwise. + bool TryRead(string cacheKey, out T result); - /// - /// Tries the read from cache asynchronously. - /// - /// - /// The cache key. - /// Task<Tuple<System.Boolean, System.Object>>. - Task> TryReadAsync(string cacheKey); + /// + /// Tries the read from cache asynchronously. + /// + /// + /// The cache key. + /// Task<Tuple<System.Boolean, System.Object>>. + Task> TryReadAsync(string cacheKey); - /// - /// Writes to cache. - /// - /// The cache key. - /// The value. - /// The policy. - void Write(string cacheKey, object? value, CachePolicy? policy); + /// + /// Writes to cache. + /// + /// The cache key. + /// The value. + /// The policy. + void Write(string cacheKey, object? value, CachePolicy? policy); - /// - /// Writes to cache asynchronously. - /// - /// The cache key. - /// The value. - /// The policy. - /// - /// Task. - /// - Task WriteAsync(string cacheKey, object? value, CachePolicy? policy); - } + /// + /// Writes to cache asynchronously. + /// + /// The cache key. + /// The value. + /// The policy. + /// + /// Task. + /// + Task WriteAsync(string cacheKey, object? value, CachePolicy? policy); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/ObjectCacheAdapter.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/ObjectCacheAdapter.cs index c1dd85a8e..f6d25f567 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/ObjectCacheAdapter.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/ObjectCacheAdapter.cs @@ -1,174 +1,173 @@ using System.Runtime.Caching; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// Class ObjectCacheAdapter. +/// +/// +public class ObjectCacheAdapter : ICacheAdapter { + readonly ObjectCache m_ObjectCache; + /// - /// Class ObjectCacheAdapter. + /// Initializes a new instance of the class. /// - /// - public class ObjectCacheAdapter : ICacheAdapter + /// The object cache. + public ObjectCacheAdapter(ObjectCache objectCache) { - readonly ObjectCache m_ObjectCache; - - /// - /// Initializes a new instance of the class. - /// - /// The object cache. - public ObjectCacheAdapter(ObjectCache objectCache) - { - m_ObjectCache = objectCache; - } + m_ObjectCache = objectCache; + } - /// - /// Clears the cache. - /// - public void Clear() - { - var memoryCache = m_ObjectCache as MemoryCache; - memoryCache?.Trim(100); //this wont' actually trim 100%, but it helps - foreach (var item in m_ObjectCache) - m_ObjectCache.Remove(item.Key); - } + /// + /// Clears the cache. + /// + public void Clear() + { + var memoryCache = m_ObjectCache as MemoryCache; + memoryCache?.Trim(100); //this wont' actually trim 100%, but it helps + foreach (var item in m_ObjectCache) + m_ObjectCache.Remove(item.Key); + } - /// - /// Clears the cache asynchronously. - /// - /// Task. - public Task ClearAsync() - { - Clear(); - return Task.CompletedTask; - } + /// + /// Clears the cache asynchronously. + /// + /// Task. + public Task ClearAsync() + { + Clear(); + return Task.CompletedTask; + } - /// - /// Invalidates the cache. - /// - /// The cache key. - /// - public void Invalidate(string cacheKey) - { - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); + /// + /// Invalidates the cache. + /// + /// The cache key. + /// + public void Invalidate(string cacheKey) + { + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - m_ObjectCache.Remove(cacheKey); - } + m_ObjectCache.Remove(cacheKey); + } - /// - /// Invalidates the cache asynchronously. - /// - /// The cache key. - /// Task. - public Task InvalidateAsync(string cacheKey) - { - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); + /// + /// Invalidates the cache asynchronously. + /// + /// The cache key. + /// Task. + public Task InvalidateAsync(string cacheKey) + { + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - m_ObjectCache.Remove(cacheKey); - return Task.CompletedTask; - } + m_ObjectCache.Remove(cacheKey); + return Task.CompletedTask; + } #nullable disable - /// - /// Tries the read from cache. - /// - /// - /// The cache key. - /// The result. - /// true if XXXX, false otherwise. - /// - /// - public bool TryRead(string cacheKey, out T result) - { - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); + /// + /// Tries the read from cache. + /// + /// + /// The cache key. + /// The result. + /// true if XXXX, false otherwise. + /// + /// + public bool TryRead(string cacheKey, out T result) + { + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - var cacheItem = m_ObjectCache.GetCacheItem(cacheKey, null); - if (cacheItem == null) - { - result = default; - return false; - } + var cacheItem = m_ObjectCache.GetCacheItem(cacheKey, null); + if (cacheItem == null) + { + result = default; + return false; + } - //Nulls can't be stored in a cache, so we simulate it using NullObject.Default. - if (cacheItem.Value == NullObject.Default) - { - result = default; - return true; - } + //Nulls can't be stored in a cache, so we simulate it using NullObject.Default. + if (cacheItem.Value == NullObject.Default) + { + result = default; + return true; + } - if (!(cacheItem.Value is T)) - throw new InvalidOperationException($"Cache is corrupted. Cache Key \"{cacheKey}\" is a {cacheItem.Value.GetType().Name} not a {typeof(T).Name}"); + if (!(cacheItem.Value is T)) + throw new InvalidOperationException($"Cache is corrupted. Cache Key \"{cacheKey}\" is a {cacheItem.Value.GetType().Name} not a {typeof(T).Name}"); - result = (T)cacheItem.Value; + result = (T)cacheItem.Value; - return true; - } + return true; + } #nullable restore - /// - /// try read from cache as an asynchronous operation. - /// - /// - /// The cache key. - /// Task<Tuple<System.Boolean, System.Object>>. - public Task> TryReadAsync(string cacheKey) - { - bool result2 = TryRead(cacheKey, out T result); - return Task.FromResult(new CacheReadResult(result2, result)); - } + /// + /// try read from cache as an asynchronous operation. + /// + /// + /// The cache key. + /// Task<Tuple<System.Boolean, System.Object>>. + public Task> TryReadAsync(string cacheKey) + { + bool result2 = TryRead(cacheKey, out T result); + return Task.FromResult(new CacheReadResult(result2, result)); + } - /// - /// Writes to cache. - /// - /// The cache key. - /// The value. - /// The policy. - /// - public void Write(string cacheKey, object? value, CachePolicy? policy) - { - if (string.IsNullOrEmpty(cacheKey)) - throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); - - //Nulls can't be stored in a cache, so we simulate it using NullObject.Default. - if (value == null) - value = NullObject.Default; - - var mappedPolicy = new CacheItemPolicy(); - if (policy != null) - { - if (policy.AbsoluteExpiration.HasValue) - mappedPolicy.AbsoluteExpiration = policy.AbsoluteExpiration.Value; - if (policy.SlidingExpiration.HasValue) - mappedPolicy.SlidingExpiration = policy.SlidingExpiration.Value; - } - - m_ObjectCache.Set(new CacheItem(cacheKey, value), mappedPolicy); - } + /// + /// Writes to cache. + /// + /// The cache key. + /// The value. + /// The policy. + /// + public void Write(string cacheKey, object? value, CachePolicy? policy) + { + if (string.IsNullOrEmpty(cacheKey)) + throw new ArgumentException($"{nameof(cacheKey)} is null or empty.", nameof(cacheKey)); + + //Nulls can't be stored in a cache, so we simulate it using NullObject.Default. + if (value == null) + value = NullObject.Default; - /// - /// Writes to cache asynchronously. - /// - /// The cache key. - /// The value. - /// The policy. - /// - /// Task. - /// - public Task WriteAsync(string cacheKey, object? value, CachePolicy? policy) + var mappedPolicy = new CacheItemPolicy(); + if (policy != null) { - Write(cacheKey, value, policy); - return Task.CompletedTask; + if (policy.AbsoluteExpiration.HasValue) + mappedPolicy.AbsoluteExpiration = policy.AbsoluteExpiration.Value; + if (policy.SlidingExpiration.HasValue) + mappedPolicy.SlidingExpiration = policy.SlidingExpiration.Value; } - class NullObject - { - public static readonly NullObject Default = new NullObject(); + m_ObjectCache.Set(new CacheItem(cacheKey, value), mappedPolicy); + } - NullObject() - { - } + /// + /// Writes to cache asynchronously. + /// + /// The cache key. + /// The value. + /// The policy. + /// + /// Task. + /// + public Task WriteAsync(string cacheKey, object? value, CachePolicy? policy) + { + Write(cacheKey, value, policy); + return Task.CompletedTask; + } + + class NullObject + { + public static readonly NullObject Default = new NullObject(); + + NullObject() + { } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationExecutionToken`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationExecutionToken`2.cs index ea8b5e893..7b175eb7b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationExecutionToken`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationExecutionToken`2.cs @@ -1,51 +1,50 @@ using System.Data.Common; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Core +namespace Tortuga.Chain.Core; + +/// +/// This class represents the actual preparation and execution of a operation that isn't dependent on a DbCommand. +/// +/// The type of the t connection. +/// The type of the t transaction. +/// +public class OperationExecutionToken : ExecutionToken + where TConnection : DbConnection + where TTransaction : DbTransaction { + readonly IOperationDataSource m_DataSource; + /// - /// This class represents the actual preparation and execution of a operation that isn't dependent on a DbCommand. + /// Initializes a new instance of the class. /// - /// The type of the t connection. - /// The type of the t transaction. - /// - public class OperationExecutionToken : ExecutionToken - where TConnection : DbConnection - where TTransaction : DbTransaction + /// The data source. + /// Name of the operation. This is used for logging. + public OperationExecutionToken(IOperationDataSource dataSource, string operationName) + : base(dataSource, operationName, null, CommandType.Text) { - readonly IOperationDataSource m_DataSource; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. This is used for logging. - public OperationExecutionToken(IOperationDataSource dataSource, string operationName) - : base(dataSource, operationName, null, CommandType.Text) - { - m_DataSource = dataSource; - } + m_DataSource = dataSource; + } - /// - /// Executes the specified implementation. - /// - /// The implementation. - /// The state. - public int? Execute(OperationImplementation implementation, object? state) - { - return m_DataSource.Execute(this, implementation, state); - } + /// + /// Executes the specified implementation. + /// + /// The implementation. + /// The state. + public int? Execute(OperationImplementation implementation, object? state) + { + return m_DataSource.Execute(this, implementation, state); + } - /// - /// Executes the specified implementation asynchronously. - /// - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - public Task ExecuteAsync(OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - return m_DataSource.ExecuteAsync(this, implementation, cancellationToken, state); - } + /// + /// Executes the specified implementation asynchronously. + /// + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + public Task ExecuteAsync(OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + return m_DataSource.ExecuteAsync(this, implementation, cancellationToken, state); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementation.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementation.cs index d4ff68085..50d99d17d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementation.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementation.cs @@ -1,16 +1,15 @@ using System.Data.Common; -namespace Tortuga.Chain.Core -{ - /// - /// The implementation of an operation from an OperationBuilder. - /// - /// The type of the connection. - /// The type of the transaction. - /// The connection. - /// The transaction. - /// System.Nullable<System.Int32>. - public delegate int? OperationImplementation(TConnection connection, TTransaction? transaction) - where TConnection : DbConnection - where TTransaction : DbTransaction; -} +namespace Tortuga.Chain.Core; + +/// +/// The implementation of an operation from an OperationBuilder. +/// +/// The type of the connection. +/// The type of the transaction. +/// The connection. +/// The transaction. +/// System.Nullable<System.Int32>. +public delegate int? OperationImplementation(TConnection connection, TTransaction? transaction) + where TConnection : DbConnection + where TTransaction : DbTransaction; diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementationAsync.cs b/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementationAsync.cs index 2da724f3b..c1467725c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementationAsync.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Core/OperationImplementationAsync.cs @@ -1,17 +1,16 @@ using System.Data.Common; -namespace Tortuga.Chain.Core -{ - /// - /// The implementation of an operation from an OperationBuilder. - /// - /// The type of the connection. - /// The type of the transaction. - /// The connection. - /// The transaction. - /// The cancellation token. - /// Task<System.Nullable<System.Int32>>. - public delegate Task OperationImplementationAsync(TConnection connection, TTransaction? transaction, CancellationToken cancellationToken) - where TConnection : DbConnection - where TTransaction : DbTransaction; -} +namespace Tortuga.Chain.Core; + +/// +/// The implementation of an operation from an OperationBuilder. +/// +/// The type of the connection. +/// The type of the transaction. +/// The connection. +/// The transaction. +/// The cancellation token. +/// Task<System.Nullable<System.Int32>>. +public delegate Task OperationImplementationAsync(TConnection connection, TTransaction? transaction, CancellationToken cancellationToken) + where TConnection : DbConnection + where TTransaction : DbTransaction; diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DBCommandExtensions.cs b/Tortuga.Chain/Tortuga.Chain.Core/DBCommandExtensions.cs index 6e95b52f0..b7c532bc8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DBCommandExtensions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DBCommandExtensions.cs @@ -1,15 +1,14 @@ using System.Data.Common; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +static class DbCommandExtensions { - static class DbCommandExtensions + public static IEnumerable Enumerate(this DbParameterCollection collection) { - public static IEnumerable Enumerate(this DbParameterCollection collection) + for (int i = 0; i < collection.Count; i++) { - for (int i = 0; i < collection.Count; i++) - { - yield return collection[i]; - } + yield return collection[i]; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource.cs index b0dfea440..7694c5994 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource.cs @@ -5,333 +5,332 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Class DataSource. +/// +public abstract class DataSource : IDataSource { /// - /// Class DataSource. + /// Initializes a new instance of the class. /// - public abstract class DataSource : IDataSource + /// Optional settings object. + protected DataSource(DataSourceSettings? settings) { - /// - /// Initializes a new instance of the class. - /// - /// Optional settings object. - protected DataSource(DataSourceSettings? settings) + if (settings != null) { - if (settings != null) - { - DefaultCommandTimeout = settings.DefaultCommandTimeout; - StrictMode = settings.StrictMode ?? false; - SequentialAccessMode = settings.SequentialAccessMode ?? false; - SuppressGlobalEvents = settings.SuppressGlobalEvents ?? false; - } + DefaultCommandTimeout = settings.DefaultCommandTimeout; + StrictMode = settings.StrictMode ?? false; + SequentialAccessMode = settings.SequentialAccessMode ?? false; + SuppressGlobalEvents = settings.SuppressGlobalEvents ?? false; } + } - /// - /// Raised when a executionDetails is canceled in any dispatcher. - /// - /// This is not used for timeouts. - public static event EventHandler? GlobalExecutionCanceled; - - /// - /// Raised when a procedure call fails in any dispatcher. - /// - public static event EventHandler? GlobalExecutionError; - - /// - /// Raised when a procedure call is successfully completed in any dispatcher - /// - public static event EventHandler? GlobalExecutionFinished; - - /// - /// Raised when a procedure call is started in any dispatcher - /// - public static event EventHandler? GlobalExecutionStarted; - - /// - /// Raised when a executionDetails is canceled. - /// - /// This is not used for timeouts. - public event EventHandler? ExecutionCanceled; - - /// - /// Raised when a procedure call fails. - /// - public event EventHandler? ExecutionError; - - /// - /// Raised when a procedure call is successfully completed - /// - public event EventHandler? ExecutionFinished; - - /// - /// Raised when a procedure call is started - /// - public event EventHandler? ExecutionStarted; - - /// - /// Gets or sets the audit rules. - /// - /// - /// The audit rules. - /// - public AuditRuleCollection AuditRules { get; protected set; } = AuditRuleCollection.Empty; - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public abstract ICacheAdapter Cache { get; } - - /// - /// Gets the database metadata. - /// - /// - /// The database metadata. - /// - /// Data sources are expected to shadow this with their specific version. - public IDatabaseMetadataCache DatabaseMetadata { get { return OnGetDatabaseMetadata(); } } - - /// - /// Gets or sets the default command timeout. - /// - /// The default command timeout. - public TimeSpan? DefaultCommandTimeout { get; } - - /// - /// Gets the name of the data source. - /// - /// - /// The name of the data source. - /// - public string? Name { get; protected set; } - - /// - /// Gets a value indicating whether strict mode is enabled. - /// - /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. - public bool StrictMode { get; } - - /// - /// Gets a value indicating whether to use CommandBehavior.SequentialAccess. - /// - /// If true, this data source will not honor global event handlers. - /// - /// Disable for general database access. Enable when working with very large objects. - /// For more information see https://docs.microsoft.com/en-us/archive/blogs/adonet/using-sqldatareaders-new-async-methods-in-net-4-5 - /// - public bool SequentialAccessMode { get; } - - /// - /// Gets or sets a value indicating whether to suppress global events. - /// - /// If true, this data source will not honor global event handlers. - public bool SuppressGlobalEvents { get; } - - /// - /// Gets or sets the user value to use with audit rules. - /// - /// - /// The user value. - /// - public object? UserValue { get; protected set; } - - /// - /// Gets the default cache. - /// - /// - /// The default cache. - /// - protected static ICacheAdapter DefaultCache { get; } = new ObjectCacheAdapter(MemoryCache.Default); - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// The extension cache. - protected abstract ConcurrentDictionary ExtensionCache { get; } - - /// - /// Gets the extension data. - /// - /// The type of extension data desired. - /// T. - /// Chain extensions can use this to store data source specific data. The key should be a data type defined by the extension. - /// Transactional data sources should override this method and return the value held by their parent data source. - public TTKey GetExtensionData() - where TTKey : new() - { - return (TTKey)ExtensionCache.GetOrAdd(typeof(TTKey), x => new TTKey()); - } + /// + /// Raised when a executionDetails is canceled in any dispatcher. + /// + /// This is not used for timeouts. + public static event EventHandler? GlobalExecutionCanceled; - /// - /// Raises the event. - /// - /// The instance containing the event data. - /// e - e is null. - [EditorBrowsable(EditorBrowsableState.Never)] - public void OnExecutionCanceled(ExecutionEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + /// + /// Raised when a procedure call fails in any dispatcher. + /// + public static event EventHandler? GlobalExecutionError; - ExecutionCanceled?.Invoke(this, e); - if (!SuppressGlobalEvents && GlobalExecutionCanceled != null) - GlobalExecutionCanceled(this, e); - } + /// + /// Raised when a procedure call is successfully completed in any dispatcher + /// + public static event EventHandler? GlobalExecutionFinished; - /// - /// Raises the event. - /// - /// The instance containing the event data. - /// e - e is null. - [EditorBrowsable(EditorBrowsableState.Never)] - public void OnExecutionError(ExecutionEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + /// + /// Raised when a procedure call is started in any dispatcher + /// + public static event EventHandler? GlobalExecutionStarted; - ExecutionError?.Invoke(this, e); - if (!SuppressGlobalEvents && GlobalExecutionError != null) - GlobalExecutionError(this, e); - } + /// + /// Raised when a executionDetails is canceled. + /// + /// This is not used for timeouts. + public event EventHandler? ExecutionCanceled; - /// - /// Raises the event. - /// - /// The instance containing the event data. - /// e - e is null. - [EditorBrowsable(EditorBrowsableState.Never)] - public void OnExecutionFinished(ExecutionEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + /// + /// Raised when a procedure call fails. + /// + public event EventHandler? ExecutionError; - ExecutionFinished?.Invoke(this, e); - if (!SuppressGlobalEvents && GlobalExecutionFinished != null) - GlobalExecutionFinished(this, e); - } + /// + /// Raised when a procedure call is successfully completed + /// + public event EventHandler? ExecutionFinished; - /// - /// Raises the event. - /// - /// The instance containing the event data. - /// e - e is null. - [EditorBrowsable(EditorBrowsableState.Never)] - public void OnExecutionStarted(ExecutionEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + /// + /// Raised when a procedure call is started + /// + public event EventHandler? ExecutionStarted; - ExecutionStarted?.Invoke(this, e); - if (!SuppressGlobalEvents && GlobalExecutionStarted != null) - GlobalExecutionStarted(this, e); - } + /// + /// Gets or sets the audit rules. + /// + /// + /// The audit rules. + /// + public AuditRuleCollection AuditRules { get; protected set; } = AuditRuleCollection.Empty; - /// - /// Tests the connection. - /// - public abstract void TestConnection(); - - /// - /// Tests the connection asynchronously. - /// - /// - public abstract Task TestConnectionAsync(); - - /// - /// Data sources can use this to indicate an executionDetails was canceled. - /// - /// The executionDetails. - /// The start time. - /// The end time. - /// User defined state, usually used for logging. - /// executionDetails - executionDetails is null. - /// This is not used for timeouts. - protected void OnExecutionCanceled(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, object? state) - { - if (executionDetails == null) - throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + /// + /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. + /// + public abstract ICacheAdapter Cache { get; } - ExecutionCanceled?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, state)); - if (!SuppressGlobalEvents) - GlobalExecutionCanceled?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, state)); - } + /// + /// Gets the database metadata. + /// + /// + /// The database metadata. + /// + /// Data sources are expected to shadow this with their specific version. + public IDatabaseMetadataCache DatabaseMetadata { get { return OnGetDatabaseMetadata(); } } - /// - /// Data sources can use this to indicate an error has occurred. - /// - /// The executionDetails. - /// The start time. - /// The end time. - /// The error. - /// User defined state, usually used for logging. - /// executionDetails - executionDetails is null. - /// or - /// error - error is null. - protected void OnExecutionError(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, Exception error, object? state) - { - if (executionDetails == null) - throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); - if (error == null) - throw new ArgumentNullException(nameof(error), $"{nameof(error)} is null."); - - ExecutionError?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, error, state)); - if (!SuppressGlobalEvents) - GlobalExecutionError?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, error, state)); - } + /// + /// Gets or sets the default command timeout. + /// + /// The default command timeout. + public TimeSpan? DefaultCommandTimeout { get; } - /// - /// Data sources can use this to indicate an executionDetails has finished. - /// - /// The executionDetails. - /// The start time. - /// The end time. - /// The number of rows affected. - /// User defined state, usually used for logging. - /// executionDetails - executionDetails is null. - protected void OnExecutionFinished(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, int? rowsAffected, object? state) - { - if (executionDetails == null) - throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + /// + /// Gets the name of the data source. + /// + /// + /// The name of the data source. + /// + public string? Name { get; protected set; } - ExecutionFinished?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, rowsAffected, state)); - if (!SuppressGlobalEvents) - GlobalExecutionFinished?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, rowsAffected, state)); - } + /// + /// Gets a value indicating whether to use CommandBehavior.SequentialAccess. + /// + /// If true, this data source will not honor global event handlers. + /// + /// Disable for general database access. Enable when working with very large objects. + /// For more information see https://docs.microsoft.com/en-us/archive/blogs/adonet/using-sqldatareaders-new-async-methods-in-net-4-5 + /// + public bool SequentialAccessMode { get; } - /// - /// Data sources can use this to indicate an executionDetails has begun. - /// - /// The executionDetails. - /// The start time. - /// User defined state, usually used for logging. - /// executionDetails - executionDetails is null. - protected void OnExecutionStarted(ExecutionToken executionDetails, DateTimeOffset startTime, object? state) - { - if (executionDetails == null) - throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + /// + /// Gets a value indicating whether strict mode is enabled. + /// + /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. + public bool StrictMode { get; } - ExecutionStarted?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, state)); - if (!SuppressGlobalEvents) - GlobalExecutionStarted?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, state)); - } + /// + /// Gets or sets a value indicating whether to suppress global events. + /// + /// If true, this data source will not honor global event handlers. + public bool SuppressGlobalEvents { get; } + + /// + /// Gets or sets the user value to use with audit rules. + /// + /// + /// The user value. + /// + public object? UserValue { get; protected set; } + + /// + /// Gets the default cache. + /// + /// + /// The default cache. + /// + protected static ICacheAdapter DefaultCache { get; } = new ObjectCacheAdapter(MemoryCache.Default); + + /// + /// The extension cache is used by extensions to store data source specific information. + /// + /// The extension cache. + protected abstract ConcurrentDictionary ExtensionCache { get; } + + /// + /// Gets the extension data. + /// + /// The type of extension data desired. + /// T. + /// Chain extensions can use this to store data source specific data. The key should be a data type defined by the extension. + /// Transactional data sources should override this method and return the value held by their parent data source. + public TTKey GetExtensionData() + where TTKey : new() + { + return (TTKey)ExtensionCache.GetOrAdd(typeof(TTKey), x => new TTKey()); + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + /// e - e is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public void OnExecutionCanceled(ExecutionEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + + ExecutionCanceled?.Invoke(this, e); + if (!SuppressGlobalEvents && GlobalExecutionCanceled != null) + GlobalExecutionCanceled(this, e); + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + /// e - e is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public void OnExecutionError(ExecutionEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + + ExecutionError?.Invoke(this, e); + if (!SuppressGlobalEvents && GlobalExecutionError != null) + GlobalExecutionError(this, e); + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + /// e - e is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public void OnExecutionFinished(ExecutionEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + + ExecutionFinished?.Invoke(this, e); + if (!SuppressGlobalEvents && GlobalExecutionFinished != null) + GlobalExecutionFinished(this, e); + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + /// e - e is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public void OnExecutionStarted(ExecutionEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + + ExecutionStarted?.Invoke(this, e); + if (!SuppressGlobalEvents && GlobalExecutionStarted != null) + GlobalExecutionStarted(this, e); + } - /// - /// Called when Database.DatabaseMetadata is invoked. - /// - /// - protected abstract IDatabaseMetadataCache OnGetDatabaseMetadata(); - - ///// - ///// Creates a multi-batcher. This is used by InsertMultipleBatch; - ///// - ///// The type of the object. - ///// The call back used to insert the batch. - ///// The objects to insert. - ///// Size of the batch. - ///// ILink<System.Int32>. - //protected ILink CreateMultiBatcher(Func, ILink> callBack, IEnumerable objects, int batchSize) - //{ - // return new MultiBatcher(this, callBack, objects, batchSize); - //} + /// + /// Tests the connection. + /// + public abstract void TestConnection(); + + /// + /// Tests the connection asynchronously. + /// + /// + public abstract Task TestConnectionAsync(); + + /// + /// Data sources can use this to indicate an executionDetails was canceled. + /// + /// The executionDetails. + /// The start time. + /// The end time. + /// User defined state, usually used for logging. + /// executionDetails - executionDetails is null. + /// This is not used for timeouts. + protected void OnExecutionCanceled(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, object? state) + { + if (executionDetails == null) + throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + + ExecutionCanceled?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, state)); + if (!SuppressGlobalEvents) + GlobalExecutionCanceled?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, state)); + } + + /// + /// Data sources can use this to indicate an error has occurred. + /// + /// The executionDetails. + /// The start time. + /// The end time. + /// The error. + /// User defined state, usually used for logging. + /// executionDetails - executionDetails is null. + /// or + /// error - error is null. + protected void OnExecutionError(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, Exception error, object? state) + { + if (executionDetails == null) + throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + if (error == null) + throw new ArgumentNullException(nameof(error), $"{nameof(error)} is null."); + + ExecutionError?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, error, state)); + if (!SuppressGlobalEvents) + GlobalExecutionError?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, error, state)); } + + /// + /// Data sources can use this to indicate an executionDetails has finished. + /// + /// The executionDetails. + /// The start time. + /// The end time. + /// The number of rows affected. + /// User defined state, usually used for logging. + /// executionDetails - executionDetails is null. + protected void OnExecutionFinished(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, int? rowsAffected, object? state) + { + if (executionDetails == null) + throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + + ExecutionFinished?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, rowsAffected, state)); + if (!SuppressGlobalEvents) + GlobalExecutionFinished?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, endTime, rowsAffected, state)); + } + + /// + /// Data sources can use this to indicate an executionDetails has begun. + /// + /// The executionDetails. + /// The start time. + /// User defined state, usually used for logging. + /// executionDetails - executionDetails is null. + protected void OnExecutionStarted(ExecutionToken executionDetails, DateTimeOffset startTime, object? state) + { + if (executionDetails == null) + throw new ArgumentNullException(nameof(executionDetails), $"{nameof(executionDetails)} is null."); + + ExecutionStarted?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, state)); + if (!SuppressGlobalEvents) + GlobalExecutionStarted?.Invoke(this, new ExecutionEventArgs(executionDetails, startTime, state)); + } + + /// + /// Called when Database.DatabaseMetadata is invoked. + /// + /// + protected abstract IDatabaseMetadataCache OnGetDatabaseMetadata(); + + ///// + ///// Creates a multi-batcher. This is used by InsertMultipleBatch; + ///// + ///// The type of the object. + ///// The call back used to insert the batch. + ///// The objects to insert. + ///// Size of the batch. + ///// ILink<System.Int32>. + //protected ILink CreateMultiBatcher(Func, ILink> callBack, IEnumerable objects, int batchSize) + //{ + // return new MultiBatcher(this, callBack, objects, batchSize); + //} } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSourceSettings.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSourceSettings.cs index d9c94449c..645f90c1c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSourceSettings.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSourceSettings.cs @@ -1,40 +1,38 @@ -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// This class is used to modify settings that are not represented by the connection string. +/// +public class DataSourceSettings { /// - /// This class is used to modify settings that are not represented by the connection string. + /// Gets or sets the default command timeout. /// - public class DataSourceSettings - { - /// - /// Gets or sets the default command timeout. - /// - /// The default command timeout. - /// Leave null to inherit settings from the parent data source. - public TimeSpan? DefaultCommandTimeout { get; set; } - - /// - /// Gets or sets a value indicating whether strict mode is enabled. - /// - /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. - /// Leave null to inherit settings from the parent data source. - public bool? StrictMode { get; set; } + /// The default command timeout. + /// Leave null to inherit settings from the parent data source. + public TimeSpan? DefaultCommandTimeout { get; set; } - /// - /// Gets or sets a value indicating whether to suppress global events. - /// - /// If true, this data source will not honor global event handlers. - /// Leave null to inherit settings from the parent data source. - public bool? SuppressGlobalEvents { get; set; } + /// + /// Gets or sets a value indicating whether to use CommandBehavior.SequentialAccess. + /// + /// If true, this data source will not honor global event handlers. + /// Leave null to inherit settings from the parent data source. + /// Disable for general database access. Enable when working with very large objects. + /// For more information see https://docs.microsoft.com/en-us/archive/blogs/adonet/using-sqldatareaders-new-async-methods-in-net-4-5 + /// + public bool? SequentialAccessMode { get; set; } + /// + /// Gets or sets a value indicating whether strict mode is enabled. + /// + /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. + /// Leave null to inherit settings from the parent data source. + public bool? StrictMode { get; set; } - /// - /// Gets or sets a value indicating whether to use CommandBehavior.SequentialAccess. - /// - /// If true, this data source will not honor global event handlers. - /// Leave null to inherit settings from the parent data source. - /// Disable for general database access. Enable when working with very large objects. - /// For more information see https://docs.microsoft.com/en-us/archive/blogs/adonet/using-sqldatareaders-new-async-methods-in-net-4-5 - /// - public bool? SequentialAccessMode { get; set; } - } + /// + /// Gets or sets a value indicating whether to suppress global events. + /// + /// If true, this data source will not honor global event handlers. + /// Leave null to inherit settings from the parent data source. + public bool? SuppressGlobalEvents { get; set; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource`4.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource`4.cs index 3d82fd3f5..6e571d0b9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource`4.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/DataSource`4.cs @@ -1,82 +1,81 @@ using System.Data.Common; using Tortuga.Chain.Core; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Class DataSource. +/// +/// The type of the t connection. +/// The type of the t transaction. +/// The type of the command used. +/// The type of the t parameter type. +/// +public abstract class DataSource : DataSource, ICommandDataSource, IOperationDataSource + where TConnection : DbConnection + where TTransaction : DbTransaction + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Class DataSource. + /// Initializes a new instance of the class. /// - /// The type of the t connection. - /// The type of the t transaction. - /// The type of the command used. - /// The type of the t parameter type. - /// - public abstract class DataSource : DataSource, ICommandDataSource, IOperationDataSource - where TConnection : DbConnection - where TTransaction : DbTransaction - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// Optional settings object. - protected DataSource(DataSourceSettings? settings) : base(settings) { } + /// Optional settings object. + protected DataSource(DataSourceSettings? settings) : base(settings) { } - int? IOperationDataSource.Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) - { - return Execute(executionToken, implementation, state); - } + int? IOperationDataSource.Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + return Execute(executionToken, implementation, state); + } - int? ICommandDataSource.Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) - { - return Execute(executionToken, implementation, state); - } + int? ICommandDataSource.Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + return Execute(executionToken, implementation, state); + } - Task ICommandDataSource.ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - return ExecuteAsync(executionToken, implementation, cancellationToken, state); - } + Task ICommandDataSource.ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + return ExecuteAsync(executionToken, implementation, cancellationToken, state); + } - Task IOperationDataSource.ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - return ExecuteAsync(executionToken, implementation, cancellationToken, state); - } + Task IOperationDataSource.ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + return ExecuteAsync(executionToken, implementation, cancellationToken, state); + } - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - protected internal abstract int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + protected internal abstract int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected internal abstract int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected internal abstract int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state); - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected internal abstract Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state); + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected internal abstract Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state); - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected internal abstract Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state); - } + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected internal abstract Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IAdvancedCrudDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IAdvancedCrudDataSource.cs index a4d3b4c6f..4b38dc7ba 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IAdvancedCrudDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IAdvancedCrudDataSource.cs @@ -1,10 +1,9 @@ -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support additional CRUD operations. +/// +/// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. +public interface IAdvancedCrudDataSource : ICrudDataSource, ISupportsTruncate, ISupportsUpsert { - /// - /// Used to mark data sources that support additional CRUD operations. - /// - /// Warning: This interface is meant to simulate multiple inheritance and work-around some issues with exposing generic types. Do not implement it in client code, as new methods will be added over time. - public interface IAdvancedCrudDataSource : ICrudDataSource, ISupportsTruncate, ISupportsUpsert - { - } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ICommandDataSource`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ICommandDataSource`2.cs index 397946585..80ba1f645 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ICommandDataSource`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ICommandDataSource`2.cs @@ -1,35 +1,34 @@ using System.Data.Common; using Tortuga.Chain.Core; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// This interface exposes the execute command methods. +/// +/// The type of the t command. +/// The type of the t parameter. +/// +/// This is for internal use only. +public interface ICommandDataSource : IDataSource + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// This interface exposes the execute command methods. + /// Executes the specified operation. /// - /// The type of the t command. - /// The type of the t parameter. - /// - /// This is for internal use only. - public interface ICommandDataSource : IDataSource - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state); + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state); - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state); - } + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IDataSource.cs index b4129e6e6..a1c3620ce 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IDataSource.cs @@ -2,105 +2,104 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Interface IDataSource is used to expose a data source to appenders. +/// +public interface IDataSource { /// - /// Interface IDataSource is used to expose a data source to appenders. + /// Raised when a executionDetails is canceled. /// - public interface IDataSource - { - /// - /// Raised when a executionDetails is canceled. - /// - /// This is not used for timeouts. - event EventHandler? ExecutionCanceled; + /// This is not used for timeouts. + event EventHandler? ExecutionCanceled; - /// - /// Raised when a procedure call fails. - /// - event EventHandler? ExecutionError; + /// + /// Raised when a procedure call fails. + /// + event EventHandler? ExecutionError; - /// - /// Raised when a procedure call is successfully completed - /// - event EventHandler? ExecutionFinished; + /// + /// Raised when a procedure call is successfully completed + /// + event EventHandler? ExecutionFinished; - /// - /// Raised when a procedure call is started - /// - event EventHandler? ExecutionStarted; + /// + /// Raised when a procedure call is started + /// + event EventHandler? ExecutionStarted; - /// - /// Gets or sets the audit rules. - /// - /// - /// The audit rules. - /// - AuditRuleCollection AuditRules { get; } + /// + /// Gets or sets the audit rules. + /// + /// + /// The audit rules. + /// + AuditRuleCollection AuditRules { get; } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - ICacheAdapter Cache { get; } + /// + /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. + /// + ICacheAdapter Cache { get; } - /// - /// Gets the database metadata. - /// - /// - /// The database metadata. - /// - IDatabaseMetadataCache DatabaseMetadata { get; } + /// + /// Gets the database metadata. + /// + /// + /// The database metadata. + /// + IDatabaseMetadataCache DatabaseMetadata { get; } - /// - /// Gets the name of the data source. - /// - /// - /// The name of the data source. - /// - string? Name { get; } + /// + /// Gets the name of the data source. + /// + /// + /// The name of the data source. + /// + string? Name { get; } - /// - /// Gets or sets a value indicating whether strict mode is enabled. - /// - /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. - bool StrictMode { get; } + /// + /// Gets or sets a value indicating whether to use CommandBehavior.SequentialAccess. + /// + /// If true, this data source will not honor global event handlers. + /// Leave null to inherit settings from the parent data source. + /// Disable for general database access. Enable when working with very large objects. + /// For more information see https://docs.microsoft.com/en-us/archive/blogs/adonet/using-sqldatareaders-new-async-methods-in-net-4-5 + /// + public bool SequentialAccessMode { get; } - /// - /// Gets or sets a value indicating whether to use CommandBehavior.SequentialAccess. - /// - /// If true, this data source will not honor global event handlers. - /// Leave null to inherit settings from the parent data source. - /// Disable for general database access. Enable when working with very large objects. - /// For more information see https://docs.microsoft.com/en-us/archive/blogs/adonet/using-sqldatareaders-new-async-methods-in-net-4-5 - /// - public bool SequentialAccessMode { get; } + /// + /// Gets or sets a value indicating whether strict mode is enabled. + /// + /// Strict mode requires all properties that don't represent columns to be marked with the NotMapped attribute. + bool StrictMode { get; } - /// - /// Gets or sets the user value to use with audit rules. - /// - /// - /// The user value. - /// - object? UserValue { get; } + /// + /// Gets or sets the user value to use with audit rules. + /// + /// + /// The user value. + /// + object? UserValue { get; } - /// - /// Gets the extension data. - /// - /// The type of extension data desired. - /// T. - /// Chain extensions can use this to store data source specific data. The key should be a data type defined by the extension. - TTKey GetExtensionData() - where TTKey : new(); + /// + /// Gets the extension data. + /// + /// The type of extension data desired. + /// T. + /// Chain extensions can use this to store data source specific data. The key should be a data type defined by the extension. + TTKey GetExtensionData() + where TTKey : new(); - /// - /// Tests the connection. - /// - void TestConnection(); + /// + /// Tests the connection. + /// + void TestConnection(); - /// - /// Tests the connection asynchronously. - /// - /// - Task TestConnectionAsync(); - } + /// + /// Tests the connection asynchronously. + /// + /// + Task TestConnectionAsync(); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOpenDataSource.cs index 996c5162c..908969969 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOpenDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOpenDataSource.cs @@ -1,41 +1,40 @@ using System.Data.Common; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// This represents a data source that wraps a connection, and optional transaction, that it does not own. +/// +/// +/// This interface is primarily for testing purposes. +/// +public interface IOpenDataSource { /// - /// This represents a data source that wraps a connection, and optional transaction, that it does not own. + /// Returns the associated connection. /// - /// - /// This interface is primarily for testing purposes. - /// - public interface IOpenDataSource - { - /// - /// Returns the associated connection. - /// - DbConnection AssociatedConnection { get; } + DbConnection AssociatedConnection { get; } - /// - /// Returns the associated transaction. - /// - /// - DbTransaction? AssociatedTransaction { get; } + /// + /// Returns the associated transaction. + /// + /// + DbTransaction? AssociatedTransaction { get; } - /// - /// Closes the connection and transaction associated with this data source. - /// - void Close(); + /// + /// Closes the connection and transaction associated with this data source. + /// + void Close(); - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - bool TryCommit(); + /// + /// Tries the commit the transaction associated with this data source. + /// + /// True if there was an open transaction associated with this data source, otherwise false. + bool TryCommit(); - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - bool TryRollback(); - } -} \ No newline at end of file + /// + /// Tries the rollback the transaction associated with this data source. + /// + /// True if there was an open transaction associated with this data source, otherwise false. + bool TryRollback(); +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOperationDataSource`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOperationDataSource`2.cs index 3a0b01701..b8b7bb8d9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOperationDataSource`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IOperationDataSource`2.cs @@ -1,36 +1,35 @@ using System.Data.Common; using Tortuga.Chain.Core; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// This interface exposes the execute operation methods. +/// +/// The type of the t connection. +/// The type of the t transaction. +/// +/// This is for internal use only. +public interface IOperationDataSource : IDataSource + where TConnection : DbConnection + where TTransaction : DbTransaction { /// - /// This interface exposes the execute operation methods. + /// Executes the specified operation. /// - /// The type of the t connection. - /// The type of the t transaction. - /// - /// This is for internal use only. - public interface IOperationDataSource : IDataSource - where TConnection : DbConnection - where TTransaction : DbTransaction - { - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state); + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state); - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state); - } + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IRootDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IRootDataSource.cs index c93f2c40b..74ad76212 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IRootDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/IRootDataSource.cs @@ -1,60 +1,59 @@ using System.Data.Common; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// This is a data source from which other data sources can be created. +/// +/// +/// This interface is primarily for testing purposes. +/// +public interface IRootDataSource { /// - /// This is a data source from which other data sources can be created. + /// Begin a transaction using the default settings + /// + ITransactionalDataSource BeginTransaction(); + + /// + /// Begin a transaction using the default settings + /// + Task BeginTransactionAsync(); + + /// + /// Creates and opens a connection. + /// + /// + /// WARNING: The caller of this method is responsible for closing the connection. + DbConnection CreateConnection(); + + /// + /// Creates and opens a connection asynchronously. + /// + /// + /// WARNING: The caller of this method is responsible for closing the connection. + Task CreateConnectionAsync(); + + /// + /// Creates an open data source with a new connection. + /// + /// + /// WARNING: The caller of this method is responsible for closing the connection. + IOpenDataSource CreateOpenDataSource(); + + /// + /// Creates an open data source using the supplied connection and optional transaction. + /// + /// The connection to wrap. + /// The transaction to wrap. + /// + IOpenDataSource CreateOpenDataSource(DbConnection connection, DbTransaction? transaction = null); + + /// + /// Creates an open data source using the supplied connection and optional transaction. /// - /// - /// This interface is primarily for testing purposes. - /// - public interface IRootDataSource - { - /// - /// Begin a transaction using the default settings - /// - ITransactionalDataSource BeginTransaction(); - - /// - /// Begin a transaction using the default settings - /// - Task BeginTransactionAsync(); - - /// - /// Creates and opens a connection. - /// - /// - /// WARNING: The caller of this method is responsible for closing the connection. - DbConnection CreateConnection(); - - /// - /// Creates and opens a connection asynchronously. - /// - /// - /// WARNING: The caller of this method is responsible for closing the connection. - Task CreateConnectionAsync(); - - /// - /// Creates an open data source with a new connection. - /// - /// - /// WARNING: The caller of this method is responsible for closing the connection. - IOpenDataSource CreateOpenDataSource(); - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// - IOpenDataSource CreateOpenDataSource(DbConnection connection, DbTransaction? transaction = null); - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// - IOpenDataSource CreateOpenDataSource(IDbConnection connection, IDbTransaction? transaction = null); - } + /// The connection to wrap. + /// The transaction to wrap. + /// + IOpenDataSource CreateOpenDataSource(IDbConnection connection, IDbTransaction? transaction = null); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDelete.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDelete.cs index 4dabea700..f6c2dcc0c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDelete.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDelete.cs @@ -1,27 +1,25 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the Delete command. +/// +public interface ISupportsDelete +{ /// - /// Used to mark data sources that support the Delete command. + /// Delete an object model from the specified table. /// - public interface ISupportsDelete - { - /// - /// Delete an object model from the specified table. - /// - /// Name of the table. - /// The argument value. - /// The delete options. - /// tableName is empty.;tableName - IObjectDbCommandBuilder Delete(string tableName, TArgument argumentValue, DeleteOptions options = DeleteOptions.None) where TArgument : class; + /// Name of the table. + /// The argument value. + /// The delete options. + /// tableName is empty.;tableName + IObjectDbCommandBuilder Delete(string tableName, TArgument argumentValue, DeleteOptions options = DeleteOptions.None) where TArgument : class; - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// The argument value. - /// The delete options. - IObjectDbCommandBuilder Delete(TArgument argumentValue, DeleteOptions options = DeleteOptions.None) where TArgument : class; - } + /// + /// Delete an object model from the table indicated by the class's Table attribute. + /// + /// The argument value. + /// The delete options. + IObjectDbCommandBuilder Delete(TArgument argumentValue, DeleteOptions options = DeleteOptions.None) where TArgument : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKey.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKey.cs index f744b989e..21bc55ed3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKey.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKey.cs @@ -1,30 +1,28 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the DeleteByKey command. +/// +public interface ISupportsDeleteByKey +{ /// - /// Used to mark data sources that support the DeleteByKey command. + /// Delete by key. /// - public interface ISupportsDeleteByKey - { - /// - /// Delete by key. - /// - /// The type of the t key. - /// Name of the table. - /// The key. - /// The options. - /// ISingleRowDbCommandBuilder. - ISingleRowDbCommandBuilder DeleteByKey(string tableName, TKey key, DeleteOptions options = DeleteOptions.None) where TKey : struct; + /// The type of the t key. + /// Name of the table. + /// The key. + /// The options. + /// ISingleRowDbCommandBuilder. + ISingleRowDbCommandBuilder DeleteByKey(string tableName, TKey key, DeleteOptions options = DeleteOptions.None) where TKey : struct; - /// - /// Delete by key. - /// - /// Name of the table. - /// The key. - /// The options. - /// ISingleRowDbCommandBuilder. - ISingleRowDbCommandBuilder DeleteByKey(string tableName, string key, DeleteOptions options = DeleteOptions.None); - } + /// + /// Delete by key. + /// + /// Name of the table. + /// The key. + /// The options. + /// ISingleRowDbCommandBuilder. + ISingleRowDbCommandBuilder DeleteByKey(string tableName, string key, DeleteOptions options = DeleteOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKeyList.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKeyList.cs index b71a0702e..87a29742f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKeyList.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteByKeyList.cs @@ -1,21 +1,19 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the DeleteByKeyList command. +/// +public interface ISupportsDeleteByKeyList +{ /// - /// Used to mark data sources that support the DeleteByKeyList command. + /// Delete by key. /// - public interface ISupportsDeleteByKeyList - { - /// - /// Delete by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// The options. - /// IMultipleRowDbCommandBuilder. - IMultipleRowDbCommandBuilder DeleteByKeyList(string tableName, IEnumerable keys, DeleteOptions options = DeleteOptions.None); - } + /// The type of the t key. + /// Name of the table. + /// The keys. + /// The options. + /// IMultipleRowDbCommandBuilder. + IMultipleRowDbCommandBuilder DeleteByKeyList(string tableName, IEnumerable keys, DeleteOptions options = DeleteOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteSet.cs index f81ea9984..01536bb56 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsDeleteSet.cs @@ -1,38 +1,34 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the DeleteSet command. +/// +public interface ISupportsDeleteSet +{ /// - /// Used to mark data sources that support the DeleteSet command. + /// Delete multiple records using a where expression. /// - public interface ISupportsDeleteSet - { - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// IMultipleRowDbCommandBuilder. - IMultipleRowDbCommandBuilder DeleteSet(string tableName, string whereClause); - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - /// IMultipleRowDbCommandBuilder. - IMultipleRowDbCommandBuilder DeleteSet(string tableName, string whereClause, object? argumentValue); - + /// Name of the table. + /// The where clause. + /// IMultipleRowDbCommandBuilder. + IMultipleRowDbCommandBuilder DeleteSet(string tableName, string whereClause); - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The filter options. - IMultipleRowDbCommandBuilder DeleteSet(string tableName, object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// + /// Delete multiple records using a where expression. + /// + /// Name of the table. + /// The where clause. + /// The argument value for the where clause. + /// IMultipleRowDbCommandBuilder. + IMultipleRowDbCommandBuilder DeleteSet(string tableName, string whereClause, object? argumentValue); - } + /// + /// Delete multiple records using a filter object. + /// + /// Name of the table. + /// The filter value. + /// The filter options. + IMultipleRowDbCommandBuilder DeleteSet(string tableName, object filterValue, FilterOptions filterOptions = FilterOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsFrom.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsFrom.cs index 5cdaf3aa0..d1550228a 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsFrom.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsFrom.cs @@ -1,83 +1,81 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the From command. +/// +public interface ISupportsFrom +{ /// - /// Used to mark data sources that support the From command. + /// This is used to directly query a table or view. /// - public interface ISupportsFrom - { - /// - /// This is used to directly query a table or view. - /// - /// Name of the table or view. - /// - /// tableName is empty.;tableName - /// or - /// Table or view named + tableName + could not be found. Check to see if the user has permissions to execute this procedure. - /// - ITableDbCommandBuilder From(string tableOrViewName); + /// Name of the table or view. + /// + /// tableName is empty.;tableName + /// or + /// Table or view named + tableName + could not be found. Check to see if the user has permissions to execute this procedure. + /// + ITableDbCommandBuilder From(string tableOrViewName); - /// - /// This is used to directly query a table or view. - /// - /// Name of the table or view. - /// The where clause. Do not prefix this clause with "WHERE". - /// tableOrViewName is empty.;tableOrViewName - ITableDbCommandBuilder From(string tableOrViewName, string whereClause); + /// + /// This is used to directly query a table or view. + /// + /// Name of the table or view. + /// The where clause. Do not prefix this clause with "WHERE". + /// tableOrViewName is empty.;tableOrViewName + ITableDbCommandBuilder From(string tableOrViewName, string whereClause); - /// - /// This is used to directly query a table or view. - /// - /// Name of the table or view. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// tableOrViewName is empty.;tableOrViewName - ITableDbCommandBuilder From(string tableOrViewName, string whereClause, object argumentValue); + /// + /// This is used to directly query a table or view. + /// + /// Name of the table or view. + /// The where clause. Do not prefix this clause with "WHERE". + /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause + /// tableOrViewName is empty.;tableOrViewName + ITableDbCommandBuilder From(string tableOrViewName, string whereClause, object argumentValue); - /// - /// This is used to directly query a table or view. - /// - /// Name of the table or view. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// ITableDbCommandBuilder. - /// tableOrViewName is empty.;tableOrViewName - ITableDbCommandBuilder From(string tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None); + /// + /// This is used to directly query a table or view. + /// + /// Name of the table or view. + /// The filter value is used to generate a simple AND style WHERE clause. + /// The filter options. + /// ITableDbCommandBuilder. + /// tableOrViewName is empty.;tableOrViewName + ITableDbCommandBuilder From(string tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None); - /// - /// This is used to directly query a table or view. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ITableDbCommandBuilder From() where TObject : class; + /// + /// This is used to directly query a table or view. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ITableDbCommandBuilder From() where TObject : class; - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ITableDbCommandBuilder From(string whereClause) where TObject : class; + /// + /// This is used to directly query a table or view. + /// + /// The type of the object. + /// The where clause. Do not prefix this clause with "WHERE". + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ITableDbCommandBuilder From(string whereClause) where TObject : class; - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ITableDbCommandBuilder From(string whereClause, object argumentValue) where TObject : class; + /// + /// This is used to directly query a table or view. + /// + /// The type of the object. + /// The where clause. Do not prefix this clause with "WHERE". + /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ITableDbCommandBuilder From(string whereClause, object argumentValue) where TObject : class; - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ITableDbCommandBuilder From(object filterValue) where TObject : class; - } + /// + /// This is used to directly query a table or view. + /// + /// The type of the object. + /// The filter value is used to generate a simple AND style WHERE clause. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ITableDbCommandBuilder From(object filterValue) where TObject : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByColumn.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByColumn.cs new file mode 100644 index 000000000..5ec532c0c --- /dev/null +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByColumn.cs @@ -0,0 +1,83 @@ +using Tortuga.Chain.CommandBuilders; + +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support the GetByColumn command. +/// +public interface ISupportsGetByColumn +{ + /// + /// Gets one or more records by an arbitrary column. + /// + /// + /// Name of the table. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string tableName, string columnName, TKey key) + where TKey : struct; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// Name of the table. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string tableName, string columnName, string key); + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string columnName, TKey key) + where TObject : class + where TKey : struct; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string columnName, string key) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string columnName, short key) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string columnName, int key) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string columnName, long key) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search key. + IMultipleRowDbCommandBuilder GetByColumn(string columnName, Guid key) + where TObject : class; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByColumnList.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByColumnList.cs new file mode 100644 index 000000000..fa30cc7c0 --- /dev/null +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByColumnList.cs @@ -0,0 +1,64 @@ +using Tortuga.Chain.CommandBuilders; + +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support the GetByColumnList command. +/// +public interface ISupportsGetByColumnList +{ + /// + /// Gets one or more records by an arbitrary column. + /// + /// + /// Name of the table. + /// The name of the column to search. + /// The search keys. + IMultipleRowDbCommandBuilder GetByColumnList(string tableName, string columnName, IEnumerable keys); + + /// + /// Gets one or more records by an arbitrary column. + /// + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search keys. + IMultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search keys. + IMultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search keys. + IMultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search keys. + IMultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class; + + /// + /// Gets one or more records by an arbitrary column. + /// + /// The type of the object. Used to determine which table will be read. + /// The name of the column to search. + /// The search keys. + IMultipleRowDbCommandBuilder GetByColumnList(string columnName, IEnumerable keys) + where TObject : class; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKey.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKey.cs index a9b154c50..d47011702 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKey.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKey.cs @@ -1,85 +1,91 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the GetByKey command. +/// +public interface ISupportsGetByKey +{ /// - /// Used to mark data sources that support the GetByKey command. + /// Gets a record by its primary key. /// - public interface ISupportsGetByKey - { - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(string tableName, TKey key) - where TKey : struct; - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(string tableName, string key); + /// + /// Name of the table. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(string tableName, TKey key) + where TKey : struct; + /// + /// Gets a record by its primary key. + /// + /// Name of the table. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(string tableName, string key); - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(TKey key) - where TObject : class - where TKey : struct; + /// + /// Gets a record by its primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(TKey key) + where TObject : class + where TKey : struct; - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(string key) - where TObject : class; + /// + /// Gets a record by its primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(string key) + where TObject : class; - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(int key) - where TObject : class; + /// + /// Gets a record by its primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(short key) + where TObject : class; - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(long key) - where TObject : class; + /// + /// Gets a record by its primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(int key) + where TObject : class; - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - ISingleRowDbCommandBuilder GetByKey(Guid key) - where TObject : class; + /// + /// Gets a record by its primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(long key) + where TObject : class; - } -} + /// + /// Gets a record by its primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The key. + /// + /// This only works on tables that have a scalar primary key. + ISingleRowDbCommandBuilder GetByKey(Guid key) + where TObject : class; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKeyList.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKeyList.cs index 63db4d36b..40c16d9e4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKeyList.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsGetByKeyList.cs @@ -1,78 +1,81 @@ using System.ComponentModel; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the GetByKeyList command. +/// +public interface ISupportsGetByKeyList +{ /// - /// Used to mark data sources that support the GetByKeyList command. + /// Gets a set of records by their primary key. /// - public interface ISupportsGetByKeyList - { - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - IMultipleRowDbCommandBuilder GetByKeyList(string tableName, IEnumerable keys); - - - /// - /// Gets a set of records by their primary key. - /// - /// - /// The type of the object. Used to determine which table will be read. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) - where TObject : class; + /// + /// Name of the table. + /// The keys. + /// + /// This only works on tables that have a scalar primary key. + IMultipleRowDbCommandBuilder GetByKeyList(string tableName, IEnumerable keys); - /// - /// Gets a set of records by their primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) - where TObject : class; - - - /// - /// Gets a set of records by their primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) - where TObject : class; + /// + /// Gets a set of records by their primary key. + /// + /// + /// The type of the object. Used to determine which table will be read. + /// The keys. + /// + /// This only works on tables that have a scalar primary key. + IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) + where TObject : class; + /// + /// Gets a set of records by their primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The keys. + /// + /// This only works on tables that have a scalar primary key. + IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) + where TObject : class; - /// - /// Gets a set of records by their primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) - where TObject : class; + /// + /// Gets a set of records by their primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The keys. + /// + /// This only works on tables that have a scalar primary key. + IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) + where TObject : class; - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [Obsolete("This will be replaced by GetByColumn")] - [EditorBrowsable(EditorBrowsableState.Never)] + /// + /// Gets a set of records by their primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The keys. + /// + /// This only works on tables that have a scalar primary key. + IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) + where TObject : class; - IMultipleRowDbCommandBuilder GetByKeyList(string tableName, string keyColumn, IEnumerable keys); - } -} + /// + /// Gets a set of records by their primary key. + /// + /// The type of the object. Used to determine which table will be read. + /// The keys. + /// + /// This only works on tables that have a scalar primary key. + IMultipleRowDbCommandBuilder GetByKeyList(IEnumerable keys) + where TObject : class; + /// Gets a set of records by an unique key. + /// The type of the t key. + /// Name of the table. + /// Name of the key column. This should be a primary or unique key, but that's not enforced. + /// The keys. + /// IMultipleRowDbCommandBuilder. + [Obsolete("This will be replaced by GetByColumn")] + [EditorBrowsable(EditorBrowsableState.Never)] + IMultipleRowDbCommandBuilder GetByKeyList(string tableName, string keyColumn, IEnumerable keys); +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsert.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsert.cs index 2ca0871ef..2c4909c57 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsert.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsert.cs @@ -1,29 +1,27 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the Insert command. +/// +public interface ISupportsInsert +{ /// - /// Used to mark data sources that support the Insert command. + /// Inserts an object into the specified table. /// - public interface ISupportsInsert - { - /// - /// Inserts an object into the specified table. - /// - /// Name of the table. - /// The argument value. - /// The options for how the insert occurs. - /// - /// tableName is empty.;tableName - IObjectDbCommandBuilder Insert(string tableName, TArgument argumentValue, InsertOptions options = InsertOptions.None) where TArgument : class; + /// Name of the table. + /// The argument value. + /// The options for how the insert occurs. + /// + /// tableName is empty.;tableName + IObjectDbCommandBuilder Insert(string tableName, TArgument argumentValue, InsertOptions options = InsertOptions.None) where TArgument : class; - /// - /// Inserts an object into the specified table. - /// - /// The argument value. - /// The options for how the insert occurs. - /// - IObjectDbCommandBuilder Insert(TArgument argumentValue, InsertOptions options = InsertOptions.None) where TArgument : class; - } + /// + /// Inserts an object into the specified table. + /// + /// The argument value. + /// The options for how the insert occurs. + /// + IObjectDbCommandBuilder Insert(TArgument argumentValue, InsertOptions options = InsertOptions.None) where TArgument : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBatch.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBatch.cs index 8dd5b4299..278f76eb3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBatch.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBatch.cs @@ -1,43 +1,41 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support inserting multiple rows at once. +/// +public interface ISupportsInsertBatch { /// - /// Used to mark data sources that support inserting multiple rows at once. + /// Inserts the batch of records as one operation. /// - public interface ISupportsInsertBatch - { - /// - /// Performs a series of batch inserts. - /// - /// The type of the t object. - /// Name of the table. - /// The objects. - /// The options. - /// Tortuga.Chain.ILink<System.Int32>. - /// This operation is not atomic. It should be wrapped in a transaction. - ILink InsertMultipleBatch(string tableName, IReadOnlyList objects, InsertOptions options = InsertOptions.None) - where TObject : class; - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - ILink InsertMultipleBatch(IReadOnlyList objects, InsertOptions options = InsertOptions.None) - where TObject : class; + /// + /// The objects to insert. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + IDbCommandBuilder InsertBatch(IEnumerable objects, InsertOptions options = InsertOptions.None) + where TObject : class; - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - IDbCommandBuilder InsertBatch(IEnumerable objects, InsertOptions options = InsertOptions.None) - where TObject : class; + /// + /// Performs a series of batch inserts. + /// + /// The type of the t object. + /// Name of the table. + /// The objects. + /// The options. + /// Tortuga.Chain.ILink<System.Int32>. + /// This operation is not atomic. It should be wrapped in a transaction. + ILink InsertMultipleBatch(string tableName, IReadOnlyList objects, InsertOptions options = InsertOptions.None) + where TObject : class; - } -} \ No newline at end of file + /// + /// Inserts the batch of records as one operation. + /// + /// + /// The objects to insert. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + ILink InsertMultipleBatch(IReadOnlyList objects, InsertOptions options = InsertOptions.None) + where TObject : class; +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBulk.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBulk.cs index 976deafdd..c38b2f925 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBulk.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsInsertBulk.cs @@ -1,63 +1,62 @@ -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that supports bulk inserts. +/// +public interface ISupportsInsertBulk { /// - /// Used to mark data sources that supports bulk inserts. + /// Inserts the batch of records using bulk insert. /// - public interface ISupportsInsertBulk - { - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data table. - /// MySqlInsertBulk. - public ILink InsertBulk(string tableName, DataTable dataTable); + /// Name of the table. + /// The data table. + /// MySqlInsertBulk. + public ILink InsertBulk(string tableName, DataTable dataTable); - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data reader. - /// MySqlInsertBulk. - public ILink InsertBulk(string tableName, IDataReader dataReader); + /// + /// Inserts the batch of records using bulk insert. + /// + /// Name of the table. + /// The data reader. + /// MySqlInsertBulk. + public ILink InsertBulk(string tableName, IDataReader dataReader); - /// - /// Inserts the batch of records using bulk insert. - /// - /// - /// Name of the table. - /// The objects. - /// MySqlInsertBulk. - public ILink InsertBulk(string tableName, IEnumerable objects) where TObject : class; + /// + /// Inserts the batch of records using bulk insert. + /// + /// + /// Name of the table. + /// The objects. + /// MySqlInsertBulk. + public ILink InsertBulk(string tableName, IEnumerable objects) where TObject : class; - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data table. - /// - /// MySqlInsertBulk. - /// - public ILink InsertBulk(DataTable dataTable) where TObject : class; + /// + /// Inserts the batch of records using bulk insert. + /// + /// The type of the object. + /// The data table. + /// + /// MySqlInsertBulk. + /// + public ILink InsertBulk(DataTable dataTable) where TObject : class; - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data reader. - /// - /// MySqlInsertBulk. - /// - public ILink InsertBulk(IDataReader dataReader) where TObject : class; + /// + /// Inserts the batch of records using bulk insert. + /// + /// The type of the object. + /// The data reader. + /// + /// MySqlInsertBulk. + /// + public ILink InsertBulk(IDataReader dataReader) where TObject : class; - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The objects. - /// - /// MySqlInsertBulk. - /// - public ILink InsertBulk(IEnumerable objects) where TObject : class; - } + /// + /// Inserts the batch of records using bulk insert. + /// + /// The type of the object. + /// The objects. + /// + /// MySqlInsertBulk. + /// + public ILink InsertBulk(IEnumerable objects) where TObject : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsSqlQueries.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsSqlQueries.cs index 2fd55d37c..19fe6a01e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsSqlQueries.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsSqlQueries.cs @@ -1,17 +1,16 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support raw SQL queries. +/// +public interface ISupportsSqlQueries { /// - /// Used to mark data sources that support raw SQL queries. + /// Creates a operation based on a raw SQL statement. /// - public interface ISupportsSqlQueries - { - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - IMultipleTableDbCommandBuilder Sql(string sqlStatement, object argumentValue); - } + /// The SQL statement. + /// The argument value. + IMultipleTableDbCommandBuilder Sql(string sqlStatement, object argumentValue); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsTruncate.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsTruncate.cs index 48c2f16cc..cabbbaf89 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsTruncate.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsTruncate.cs @@ -1,19 +1,17 @@ -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; - /// - /// Used to mark datasources that support the Truncate command. - /// - public interface ISupportsTruncate - { - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public ILink Truncate(string tableName); +/// +/// Used to mark datasources that support the Truncate command. +/// +public interface ISupportsTruncate +{ + /// Truncates the specified table. + /// Name of the table to Truncate. + /// The number of rows deleted or null if the database doesn't provide that information. + public ILink Truncate(string tableName); - /// Truncates the specified table. - /// This class used to determine which table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public ILink Truncate() where TObject : class; - } + /// Truncates the specified table. + /// This class used to determine which table to Truncate. + /// The number of rows deleted or null if the database doesn't provide that information. + public ILink Truncate() where TObject : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdate.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdate.cs index bbc4316a0..5f6786f8e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdate.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdate.cs @@ -1,29 +1,26 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the Update command. +/// +public interface ISupportsUpdate +{ /// - /// Used to mark data sources that support the Update command. + /// Update an object in the specified table. /// - public interface ISupportsUpdate - { - /// - /// Update an object in the specified table. - /// - /// Name of the table. - /// The argument value. - /// The update options. - /// tableName is empty.;tableName - IObjectDbCommandBuilder Update(string tableName, TArgument argumentValue, UpdateOptions options = UpdateOptions.None) where TArgument : class; - - /// - /// Update an object in the specified table. - /// - /// The argument value. - /// The update options. - /// tableName is empty.;tableName - IObjectDbCommandBuilder Update(TArgument argumentValue, UpdateOptions options = UpdateOptions.None) where TArgument : class; + /// Name of the table. + /// The argument value. + /// The update options. + /// tableName is empty.;tableName + IObjectDbCommandBuilder Update(string tableName, TArgument argumentValue, UpdateOptions options = UpdateOptions.None) where TArgument : class; - } + /// + /// Update an object in the specified table. + /// + /// The argument value. + /// The update options. + /// tableName is empty.;tableName + IObjectDbCommandBuilder Update(TArgument argumentValue, UpdateOptions options = UpdateOptions.None) where TArgument : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKey.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKey.cs index 78a31303a..94c496c56 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKey.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKey.cs @@ -1,35 +1,33 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support the UpdateByKey command. +/// +public interface ISupportsUpdateByKey { /// - /// Used to mark data sources that support the UpdateByKey command. + /// Update a record by its primary key. /// - public interface ISupportsUpdateByKey - { - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - ISingleRowDbCommandBuilder UpdateByKey(string tableName, TArgument newValues, TKey key, UpdateOptions options = UpdateOptions.None) - where TKey : struct; + /// The type of the t argument. + /// + /// Name of the table. + /// The new values to use. + /// The key. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + ISingleRowDbCommandBuilder UpdateByKey(string tableName, TArgument newValues, TKey key, UpdateOptions options = UpdateOptions.None) + where TKey : struct; - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - ISingleRowDbCommandBuilder UpdateByKey(string tableName, TArgument newValues, string key, UpdateOptions options = UpdateOptions.None); - } + /// + /// Update a record by its primary key. + /// + /// The type of the t argument. + /// Name of the table. + /// The new values to use. + /// The key. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + ISingleRowDbCommandBuilder UpdateByKey(string tableName, TArgument newValues, string key, UpdateOptions options = UpdateOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKeyList.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKeyList.cs index 388113967..2fdb6d60b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKeyList.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateByKeyList.cs @@ -1,24 +1,22 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources -{ +namespace Tortuga.Chain.DataSources; +/// +/// Used to mark data sources that support the UpdateByKey command. +/// +public interface ISupportsUpdateByKeyList +{ /// - /// Used to mark data sources that support the UpdateByKey command. + /// Update multiple rows by key. /// - public interface ISupportsUpdateByKeyList - { - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - /// - IMultipleRowDbCommandBuilder UpdateByKeyList(string tableName, TArgument newValues, IEnumerable keys, UpdateOptions options = UpdateOptions.None); - } + /// The type of the t argument. + /// The type of the t key. + /// Name of the table. + /// The new values to use. + /// The keys. + /// Update options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + /// + IMultipleRowDbCommandBuilder UpdateByKeyList(string tableName, TArgument newValues, IEnumerable keys, UpdateOptions options = UpdateOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateSet.cs index 9cbc9dfbf..fdee0cda4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpdateSet.cs @@ -1,39 +1,37 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support the UpdateSet command. +/// +public interface ISupportsUpdateSet { /// - /// Used to mark data sources that support the UpdateSet command. + /// Update multiple records using an update expression. /// - public interface ISupportsUpdateSet - { - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - IUpdateSetDbCommandBuilder UpdateSet(string tableName, string updateExpression, UpdateOptions options = UpdateOptions.None); + /// Name of the table. + /// The update expression. + /// The update options. + /// Use .WithFilter to apply a WHERE clause. + IUpdateSetDbCommandBuilder UpdateSet(string tableName, string updateExpression, UpdateOptions options = UpdateOptions.None); - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - IUpdateSetDbCommandBuilder UpdateSet(string tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options = UpdateOptions.None); + /// + /// Update multiple records using an update expression. + /// + /// Name of the table. + /// The update expression. + /// The argument for the update expression. + /// The update options. + /// Use .WithFilter to apply a WHERE clause. + IUpdateSetDbCommandBuilder UpdateSet(string tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options = UpdateOptions.None); - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - IUpdateSetDbCommandBuilder UpdateSet(string tableName, object newValues, UpdateOptions options = UpdateOptions.None); - } + /// + /// Update multiple records using an update value. + /// + /// Name of the table. + /// The new values to use. + /// The options. + /// Use .WithFilter to apply a WHERE clause. + IUpdateSetDbCommandBuilder UpdateSet(string tableName, object newValues, UpdateOptions options = UpdateOptions.None); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpsert.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpsert.cs index e8bbdb548..e7dc48848 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpsert.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ISupportsUpsert.cs @@ -1,27 +1,26 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// Used to mark data sources that support the Upsert command. +/// +public interface ISupportsUpsert { /// - /// Used to mark data sources that support the Upsert command. + /// Perform an insert or update operation as appropriate. /// - public interface ISupportsUpsert - { - /// - /// Perform an insert or update operation as appropriate. - /// - /// Name of the table. - /// The argument value. - /// The options for how the insert/update occurs. - /// tableName is empty.;tableName - IObjectDbCommandBuilder Upsert(string tableName, TArgument argumentValue, UpsertOptions options = UpsertOptions.None) where TArgument : class; + /// Name of the table. + /// The argument value. + /// The options for how the insert/update occurs. + /// tableName is empty.;tableName + IObjectDbCommandBuilder Upsert(string tableName, TArgument argumentValue, UpsertOptions options = UpsertOptions.None) where TArgument : class; - /// - /// Perform an insert or update operation as appropriate. - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// tableName is empty.;tableName - IObjectDbCommandBuilder Upsert(TArgument argumentValue, UpsertOptions options = UpsertOptions.None) where TArgument : class; - } + /// + /// Perform an insert or update operation as appropriate. + /// + /// The argument value. + /// The options for how the insert/update occurs. + /// tableName is empty.;tableName + IObjectDbCommandBuilder Upsert(TArgument argumentValue, UpsertOptions options = UpsertOptions.None) where TArgument : class; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ITransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ITransactionalDataSource.cs index f01874dea..4f0cbaaf4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ITransactionalDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DataSources/ITransactionalDataSource.cs @@ -1,16 +1,15 @@ -namespace Tortuga.Chain.DataSources +namespace Tortuga.Chain.DataSources; + +/// +/// This is data source that is wrapped around a managed connection. +/// +/// +/// This interface is primarily for testing purposes. +/// +public interface ITransactionalDataSource : IOpenDataSource { /// - /// This is data source that is wrapped around a managed connection. + /// Commits this transaction. /// - /// - /// This interface is primarily for testing purposes. - /// - public interface ITransactionalDataSource : IOpenDataSource - { - /// - /// Commits this transaction. - /// - void Commit(); - } -} \ No newline at end of file + void Commit(); +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DeleteOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/DeleteOptions.cs index 908643e5a..4b8f6ed3a 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DeleteOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DeleteOptions.cs @@ -1,25 +1,24 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Controls what happens when performing a model-based delete +/// +[Flags] +public enum DeleteOptions { /// - /// Controls what happens when performing a model-based delete + /// Use the primary key columns for the where clause. /// - [Flags] - public enum DeleteOptions - { - /// - /// Use the primary key columns for the where clause. - /// - None = 0, + None = 0, - /// - /// Ignore the primary keys on the table and perform the delete using the Key attribute on properties to construct the where clause. - /// - /// This is generally used for heap-style tables, though technically heap tables may have primary, non-clustered keys. - UseKeyAttribute = 2, + /// + /// Ignore the primary keys on the table and perform the delete using the Key attribute on properties to construct the where clause. + /// + /// This is generally used for heap-style tables, though technically heap tables may have primary, non-clustered keys. + UseKeyAttribute = 2, - /// - /// Check the rows affected count. With this flag, an error will be thrown if the rows affected by the delete operation is zero. - /// - CheckRowsAffected = 4 - } + /// + /// Check the rows affected count. With this flag, an error will be thrown if the rows affected by the delete operation is zero. + /// + CheckRowsAffected = 4 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/DictionaryOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/DictionaryOptions.cs index a81fa954d..2cdee0d77 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/DictionaryOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/DictionaryOptions.cs @@ -1,27 +1,26 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Options for populating dictionaries. +/// +[Flags] +public enum DictionaryOptions { /// - /// Options for populating dictionaries. + /// Use the default behavior. /// - [Flags] - public enum DictionaryOptions - { - /// - /// Use the default behavior. - /// - /// If a class has more than one constructor, the default constructor will be used. - None = 0, + /// If a class has more than one constructor, the default constructor will be used. + None = 0, - /// - /// Infer which non-default constructor to use. When this option is chosen, individual properties will not be set. - /// - /// This will throw an error unless there is exactly one public, non-default constructor. - InferConstructor = 8, + /// + /// Infer which non-default constructor to use. When this option is chosen, individual properties will not be set. + /// + /// This will throw an error unless there is exactly one public, non-default constructor. + InferConstructor = 8, - /// - /// If two rows have the same key, no error will be raised. This option is not compatible with immutable dictionaries. - /// - /// This option uses IDictionary.Item[] instead of IDictionary.Add(). - DiscardDuplicates = 16, - } + /// + /// If two rows have the same key, no error will be raised. This option is not compatible with immutable dictionaries. + /// + /// This option uses IDictionary.Item[] instead of IDictionary.Add(). + DiscardDuplicates = 16, } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/ExecutionEventArgs.cs b/Tortuga.Chain/Tortuga.Chain.Core/ExecutionEventArgs.cs index df14826ba..08fc4eedf 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/ExecutionEventArgs.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/ExecutionEventArgs.cs @@ -1,122 +1,121 @@ using Tortuga.Chain.Core; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Events indicating the activities performed by a given datasource. +/// +public class ExecutionEventArgs : EventArgs { /// - /// Events indicating the activities performed by a given datasource. + /// Initializes a new instance of the class. /// - public class ExecutionEventArgs : EventArgs + /// The execution details. + /// The start time. + /// User defined state, usually used for logging. + /// executionDetails;executionDetails is null. + public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, object? state) { - /// - /// Initializes a new instance of the class. - /// - /// The execution details. - /// The start time. - /// User defined state, usually used for logging. - /// executionDetails;executionDetails is null. - public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, object? state) - { - ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); - StartTime = startTime; - State = state; - } + ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); + StartTime = startTime; + State = state; + } - /// - /// Initializes a new instance of the class. - /// - /// The execution details. - /// The start time. - /// The end time. - /// User defined state, usually used for logging. - /// executionDetails;executionDetails is null. - public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, object? state) - { - StartTime = startTime; - EndTime = endTime; - State = state; - ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); - } + /// + /// Initializes a new instance of the class. + /// + /// The execution details. + /// The start time. + /// The end time. + /// User defined state, usually used for logging. + /// executionDetails;executionDetails is null. + public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, object? state) + { + StartTime = startTime; + EndTime = endTime; + State = state; + ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); + } - /// - /// Initializes a new instance of the class. - /// - /// The execution details. - /// The start time. - /// The end time. - /// The number of rows affected. - /// User defined state, usually used for logging. - /// executionDetails;executionDetails is null. - public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, int? rowsAffected, object? state) - { - StartTime = startTime; - EndTime = endTime; - RowsAffected = rowsAffected; - State = state; - ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); - } + /// + /// Initializes a new instance of the class. + /// + /// The execution details. + /// The start time. + /// The end time. + /// The number of rows affected. + /// User defined state, usually used for logging. + /// executionDetails;executionDetails is null. + public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, int? rowsAffected, object? state) + { + StartTime = startTime; + EndTime = endTime; + RowsAffected = rowsAffected; + State = state; + ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); + } - /// - /// Initializes a new instance of the class. - /// - /// The execution details. - /// The start time. - /// The end time. - /// The error. - /// User defined state, usually used for logging. - /// executionDetails;executionDetails is null. - public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, Exception error, object? state) - { - StartTime = startTime; - EndTime = endTime; - Error = error; - State = state; - ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); - } + /// + /// Initializes a new instance of the class. + /// + /// The execution details. + /// The start time. + /// The end time. + /// The error. + /// User defined state, usually used for logging. + /// executionDetails;executionDetails is null. + public ExecutionEventArgs(ExecutionToken executionDetails, DateTimeOffset startTime, DateTimeOffset endTime, Exception error, object? state) + { + StartTime = startTime; + EndTime = endTime; + Error = error; + State = state; + ExecutionDetails = executionDetails ?? throw new ArgumentNullException(nameof(executionDetails)); + } - /// - /// Gets the duration of the request, if available. - /// - public TimeSpan? Duration => EndTime - StartTime; + /// + /// Gets the duration of the request, if available. + /// + public TimeSpan? Duration => EndTime - StartTime; - /// - /// Gets the end time. - /// - /// - /// The end time. - /// - public DateTimeOffset? EndTime { get; } + /// + /// Gets the end time. + /// + /// + /// The end time. + /// + public DateTimeOffset? EndTime { get; } - /// - /// Gets the error. - /// - /// - /// The error. - /// - public Exception? Error { get; } + /// + /// Gets the error. + /// + /// + /// The error. + /// + public Exception? Error { get; } - /// - /// Gets the details of the execution. - /// - /// Returns null or details of the execution. - /// You can cast this to a concrete type for more information. - public ExecutionToken ExecutionDetails { get; } + /// + /// Gets the details of the execution. + /// + /// Returns null or details of the execution. + /// You can cast this to a concrete type for more information. + public ExecutionToken ExecutionDetails { get; } - /// - /// If available, this shows the number of rows affected by the execution. - /// - public int? RowsAffected { get; } + /// + /// If available, this shows the number of rows affected by the execution. + /// + public int? RowsAffected { get; } - /// - /// Gets the start time. - /// - /// - /// The start time. - /// - public DateTimeOffset StartTime { get; } + /// + /// Gets the start time. + /// + /// + /// The start time. + /// + public DateTimeOffset StartTime { get; } - /// - /// Gets the user-defined state. - /// - public object? State { get; } - } + /// + /// Gets the user-defined state. + /// + public object? State { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/FilterOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/FilterOptions.cs index 77857cbf4..059203dcc 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/FilterOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/FilterOptions.cs @@ -1,19 +1,18 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Enum FilterOptions +/// +[Flags] +public enum FilterOptions { /// - /// Enum FilterOptions + /// The properties that are null will be used when constructing a WHERE clause. (e.g. "ColumnName IS NULL") /// - [Flags] - public enum FilterOptions - { - /// - /// The properties that are null will be used when constructing a WHERE clause. (e.g. "ColumnName IS NULL") - /// - None = 0, + None = 0, - /// - /// The ignore properties that are null when constructing a WHERE clause. - /// - IgnoreNullProperties = 1 - } + /// + /// The ignore properties that are null when constructing a WHERE clause. + /// + IgnoreNullProperties = 1 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource.cs b/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource.cs index 54b88c1e1..244d32a01 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource.cs @@ -6,405 +6,392 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// The GenericDbDataSource is the most simplistic of all of the data sources. The command builder only supports raw SQL, but you still have access to all of the materializers. +/// +public class GenericDbDataSource : DataSource, ISupportsSqlQueries { + readonly ICacheAdapter m_Cache; + readonly DbConnectionStringBuilder m_ConnectionBuilder; + readonly ConcurrentDictionary m_ExtensionCache; + readonly DbProviderFactory? m_Factory; + + GenericDatabaseMetadataCache m_DatabaseMetadataCache = new(); + /// - /// The GenericDbDataSource is the most simplistic of all of the data sources. The command builder only supports raw SQL, but you still have access to all of the materializers. + /// Initializes a new instance of the class. /// - public class GenericDbDataSource : DataSource, ISupportsSqlQueries + /// The factory used to get provider specific objects. + /// Name of the data source. + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + /// connectionString is null or empty.;connectionString + public GenericDbDataSource(DbProviderFactory factory, string name, string connectionString, DataSourceSettings? settings = null) : base(settings) { - readonly ICacheAdapter m_Cache; - readonly DbConnectionStringBuilder m_ConnectionBuilder; - readonly ConcurrentDictionary m_ExtensionCache; - readonly DbProviderFactory? m_Factory; - - /// - /// Initializes a new instance of the class. - /// - /// The factory used to get provider specific objects. - /// Name of the data source. - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - /// connectionString is null or empty.;connectionString - public GenericDbDataSource(DbProviderFactory factory, string name, string connectionString, DataSourceSettings? settings = null) : base(settings) - { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); - - m_Factory = factory ?? throw new ArgumentNullException(nameof(factory), $"{nameof(factory)} is null."); - m_ConnectionBuilder = factory.CreateConnectionStringBuilder() ?? throw new ArgumentException($"{nameof(factory)}.CreateConnectionStringBuilder returned a null.", nameof(factory)); - m_ConnectionBuilder.ConnectionString = connectionString; - Name = name; - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + + m_Factory = factory ?? throw new ArgumentNullException(nameof(factory), $"{nameof(factory)} is null."); + m_ConnectionBuilder = factory.CreateConnectionStringBuilder() ?? throw new ArgumentException($"{nameof(factory)}.CreateConnectionStringBuilder returned a null.", nameof(factory)); + m_ConnectionBuilder.ConnectionString = connectionString; + Name = name; + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - /// - /// Initializes a new instance of the class. - /// - /// The factory. - /// The name. - /// The connection string builder. - /// Optional settings object. - /// factory;factory is null. - /// or - /// connectionStringBuilder;connectionStringBuilder is null. - public GenericDbDataSource(DbProviderFactory factory, string name, DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) : base(settings) - { - m_Factory = factory ?? throw new ArgumentNullException(nameof(factory)); - m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder)); - Name = name; - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + /// + /// Initializes a new instance of the class. + /// + /// The factory. + /// The name. + /// The connection string builder. + /// Optional settings object. + /// factory;factory is null. + /// or + /// connectionStringBuilder;connectionStringBuilder is null. + public GenericDbDataSource(DbProviderFactory factory, string name, DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) : base(settings) + { + m_Factory = factory ?? throw new ArgumentNullException(nameof(factory)); + m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder)); + Name = name; + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - internal GenericDbDataSource(string? name, string connectionString, DataSourceSettings? settings = null) : base(settings) - { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + internal GenericDbDataSource(string? name, string connectionString, DataSourceSettings? settings = null) : base(settings) + { + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); - m_ConnectionBuilder = new DbConnectionStringBuilder() { ConnectionString = connectionString }; - Name = name; - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + m_ConnectionBuilder = new DbConnectionStringBuilder() { ConnectionString = connectionString }; + Name = name; + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - internal GenericDbDataSource(string? name, DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) : base(settings) - { - m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder)); - Name = name; - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + internal GenericDbDataSource(string? name, DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) : base(settings) + { + m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder)); + Name = name; + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override ICacheAdapter Cache => m_Cache; - - /// - /// Gets the connection string. - /// - /// - /// The connection string. - /// - internal string ConnectionString => m_ConnectionBuilder.ConnectionString; - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override ConcurrentDictionary ExtensionCache => m_ExtensionCache; - - /// - /// Creates and opens a SQL connection. - /// - /// - /// The caller of this method is responsible for closing the connection. - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - public DbConnection CreateConnection() - { - var con = OnCreateConnection(); - con.ConnectionString = ConnectionString; - con.Open(); + /// + /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. + /// + public override ICacheAdapter Cache => m_Cache; - return con; - } + /// + /// Gets the connection string. + /// + /// + /// The connection string. + /// + internal string ConnectionString => m_ConnectionBuilder.ConnectionString; - /// - /// Creates and opens a SQL connection. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public async Task CreateConnectionAsync(CancellationToken cancellationToken = default) - { - var con = OnCreateConnection(); - con.ConnectionString = ConnectionString; - await con.OpenAsync(cancellationToken).ConfigureAwait(false); - return con; - } + /// + /// The extension cache is used by extensions to store data source specific information. + /// + /// + /// The extension cache. + /// + protected override ConcurrentDictionary ExtensionCache => m_ExtensionCache; - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public MultipleTableDbCommandBuilder Sql(string sqlStatement) => new GenericDbSqlCall(this, sqlStatement, null); - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public MultipleTableDbCommandBuilder Sql(string sqlStatement, object argumentValue) => new GenericDbSqlCall(this, sqlStatement, argumentValue); - - IMultipleTableDbCommandBuilder ISupportsSqlQueries.Sql(string sqlStatement, object argumentValue) => Sql(sqlStatement, argumentValue); - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - using (var con = CreateConnection()) - using (var cmd = CreateCommand()) - { - cmd.Connection = con; - cmd.CommandText = "SELECT 1"; - cmd.ExecuteScalar(); - } - } + /// + /// Creates and opens a SQL connection. + /// + /// + /// The caller of this method is responsible for closing the connection. + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + public DbConnection CreateConnection() + { + var con = OnCreateConnection(); + con.ConnectionString = ConnectionString; + con.Open(); - /// - /// Tests the connection asynchronously. - /// - /// - public override async Task TestConnectionAsync() - { - using (var con = await CreateConnectionAsync().ConfigureAwait(false)) - using (var cmd = CreateCommand()) - { - cmd.Connection = con; - cmd.CommandText = "SELECT 1"; - await cmd.ExecuteScalarAsync().ConfigureAwait(false); - } - } + return con; + } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GenericDbDataSource")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DbProviderFactory")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "CreateCommand")] - internal virtual DbCommand CreateCommand() - { - if (m_Factory == null) - throw new InvalidOperationException("Subclasses of GenericDbDataSource that do not provide a DbProviderFactory need to override CreateCommand"); - return m_Factory.CreateCommand() ?? throw new InvalidOperationException($"CreateCommand on factory of type {m_Factory.GetType().Name} returned a null."); - } + /// + /// Creates and opens a SQL connection. + /// + /// The cancellation token. + /// + /// + /// The caller of this method is responsible for closing the connection. + /// + public async Task CreateConnectionAsync(CancellationToken cancellationToken = default) + { + var con = OnCreateConnection(); + con.ConnectionString = ConnectionString; + await con.OpenAsync(cancellationToken).ConfigureAwait(false); + return con; + } + + /// + /// Creates a operation based on a raw SQL statement. + /// + /// The SQL statement. + /// + public MultipleTableDbCommandBuilder Sql(string sqlStatement) => new GenericDbSqlCall(this, sqlStatement, null); + + /// + /// Creates a operation based on a raw SQL statement. + /// + /// The SQL statement. + /// The argument value. + /// SqlServerSqlCall. + public MultipleTableDbCommandBuilder Sql(string sqlStatement, object argumentValue) => new GenericDbSqlCall(this, sqlStatement, argumentValue); + + IMultipleTableDbCommandBuilder ISupportsSqlQueries.Sql(string sqlStatement, object argumentValue) => Sql(sqlStatement, argumentValue); - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GenericDbDataSource")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DbProviderFactory")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "CreateParameter")] - internal virtual DbParameter CreateParameter() + /// + /// Tests the connection. + /// + public override void TestConnection() + { + using (var con = CreateConnection()) + using (var cmd = CreateCommand()) { - if (m_Factory == null) - throw new InvalidOperationException("Subclasses of GenericDbDataSource that do not provide a DbProviderFactory need to override CreateParameter"); - return m_Factory.CreateParameter() ?? throw new InvalidOperationException($"CreateParameter on factory of type {m_Factory.GetType().Name} returned a null."); + cmd.Connection = con; + cmd.CommandText = "SELECT 1"; + cmd.ExecuteScalar(); } + } - /// - /// Creates an empty connection to be populated by CreateConnection. - /// - /// DbConnection. - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "OnCreateConnection")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GenericDbDataSource")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DbProviderFactory")] - internal virtual DbConnection OnCreateConnection() + /// + /// Tests the connection asynchronously. + /// + /// + public override async Task TestConnectionAsync() + { + using (var con = await CreateConnectionAsync().ConfigureAwait(false)) + using (var cmd = CreateCommand()) { - if (m_Factory == null) - throw new InvalidOperationException("Subclasses of GenericDbDataSource that do not provide a DbProviderFactory need to override OnCreateConnection"); - return m_Factory.CreateConnection() ?? throw new InvalidOperationException($"CreateConnection on factory of type {m_Factory.GetType().Name} returned a null."); + cmd.Connection = con; + cmd.CommandText = "SELECT 1"; + await cmd.ExecuteScalarAsync().ConfigureAwait(false); } + } - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected internal override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GenericDbDataSource")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DbProviderFactory")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "CreateCommand")] + internal virtual DbCommand CreateCommand() + { + if (m_Factory == null) + throw new InvalidOperationException("Subclasses of GenericDbDataSource that do not provide a DbProviderFactory need to override CreateCommand"); + return m_Factory.CreateCommand() ?? throw new InvalidOperationException($"CreateCommand on factory of type {m_Factory.GetType().Name} returned a null."); + } + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GenericDbDataSource")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DbProviderFactory")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "CreateParameter")] + internal virtual DbParameter CreateParameter() + { + if (m_Factory == null) + throw new InvalidOperationException("Subclasses of GenericDbDataSource that do not provide a DbProviderFactory need to override CreateParameter"); + return m_Factory.CreateParameter() ?? throw new InvalidOperationException($"CreateParameter on factory of type {m_Factory.GetType().Name} returned a null."); + } + + /// + /// Creates an empty connection to be populated by CreateConnection. + /// + /// DbConnection. + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "OnCreateConnection")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GenericDbDataSource")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DbProviderFactory")] + internal virtual DbConnection OnCreateConnection() + { + if (m_Factory == null) + throw new InvalidOperationException("Subclasses of GenericDbDataSource that do not provide a DbProviderFactory need to override OnCreateConnection"); + return m_Factory.CreateConnection() ?? throw new InvalidOperationException($"CreateConnection on factory of type {m_Factory.GetType().Name} returned a null."); + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected internal override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var con = CreateConnection()) { - using (var con = CreateConnection()) + using (var cmd = CreateCommand()) { - using (var cmd = CreateCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - catch (Exception ex) + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected internal override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + using (var con = CreateConnection()) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected internal override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected internal override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - try + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - using (var con = CreateConnection()) + using (var cmd = CreateCommand()) { - var rows = implementation(con, null); + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } } - catch (Exception ex) + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException + { + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; + } + else { OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); throw; } } + } - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected internal override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected internal override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try - { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - using (var cmd = CreateCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected internal override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Called when Database.DatabaseMetadata is invoked. - /// - /// - protected override IDatabaseMetadataCache OnGetDatabaseMetadata() - { - throw new NotSupportedException("This data source does not expose database metadata"); - } + /// + /// Called when Database.DatabaseMetadata is invoked. + /// + /// + protected override IDatabaseMetadataCache OnGetDatabaseMetadata() + { + return m_DatabaseMetadataCache; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource`3.cs index 8373838fc..210c962f2 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/GenericDbDataSource`3.cs @@ -1,66 +1,65 @@ using System.Data.Common; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// The GenericDbDataSource is the most simplistic of all of the data sources. The command builder only supports raw SQL, but you still have access to all of the materializers. +/// +/// The type of the t connection. +/// The type of the t command. +/// The type of the t parameter. +public partial class GenericDbDataSource : GenericDbDataSource + where TConnection : DbConnection, new() + where TCommand : DbCommand, new() + where TParameter : DbParameter, new() { /// - /// The GenericDbDataSource is the most simplistic of all of the data sources. The command builder only supports raw SQL, but you still have access to all of the materializers. + /// Initializes a new instance of the class. /// - /// The type of the t connection. - /// The type of the t command. - /// The type of the t parameter. - public partial class GenericDbDataSource : GenericDbDataSource - where TConnection : DbConnection, new() - where TCommand : DbCommand, new() - where TParameter : DbParameter, new() + /// Name of the data source. + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + public GenericDbDataSource(string? name, string connectionString, DataSourceSettings? settings = null) : base(name, connectionString, settings) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the data source. - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - public GenericDbDataSource(string? name, string connectionString, DataSourceSettings? settings = null) : base(name, connectionString, settings) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - public GenericDbDataSource(string connectionString, DataSourceSettings? settings = null) - : this(null, connectionString, settings) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + public GenericDbDataSource(string connectionString, DataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - /// - /// Initializes a new instance of the class. - /// - /// Optional name of the data source. - /// The connection string builder. - /// Optional settings object. - /// connectionStringBuilder;connectionStringBuilder is null. - public GenericDbDataSource(string? name, DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) : base(name, connectionStringBuilder, settings) - { - } + /// + /// Initializes a new instance of the class. + /// + /// Optional name of the data source. + /// The connection string builder. + /// Optional settings object. + /// connectionStringBuilder;connectionStringBuilder is null. + public GenericDbDataSource(string? name, DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) : base(name, connectionStringBuilder, settings) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The connection string builder. - /// Optional settings object. - public GenericDbDataSource(DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) - : this(null, connectionStringBuilder, settings) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The connection string builder. + /// Optional settings object. + public GenericDbDataSource(DbConnectionStringBuilder connectionStringBuilder, DataSourceSettings? settings = null) + : this(null, connectionStringBuilder, settings) + { + } - internal override DbCommand CreateCommand() => new TCommand(); + internal override DbCommand CreateCommand() => new TCommand(); - internal override DbParameter CreateParameter() => new TParameter(); + internal override DbParameter CreateParameter() => new TParameter(); - internal override DbConnection OnCreateConnection() => new TConnection(); - } + internal override DbConnection OnCreateConnection() => new TConnection(); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/ICacheLink`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/ICacheLink`1.cs index 90d714c86..e841f820b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/ICacheLink`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/ICacheLink`1.cs @@ -1,13 +1,12 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This represents an appender that includes a caching capability. +/// +public interface ICacheLink : ILink { /// - /// This represents an appender that includes a caching capability. + /// Instructs the appender to invalidate any cache keys that it created or updated. /// - public interface ICacheLink : ILink - { - /// - /// Instructs the appender to invalidate any cache keys that it created or updated. - /// - void Invalidate(); - } -} \ No newline at end of file + void Invalidate(); +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/IConstructibleMaterializer`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/IConstructibleMaterializer`1.cs index e2b49aba6..7ec78fa6e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/IConstructibleMaterializer`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/IConstructibleMaterializer`1.cs @@ -1,158 +1,157 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This interface denotes an materializer that allows overriding the constructor logic. This +/// includes the ability to limit the list of columns being populated. +/// +/// The type of the t result. +/// +public interface IConstructibleMaterializer : ILink { /// - /// This interface denotes an materializer that allows overriding the constructor logic. This - /// includes the ability to limit the list of columns being populated. + /// Excludes the properties from the list of what will be populated in the object. /// - /// The type of the t result. - /// - public interface IConstructibleMaterializer : ILink - { - /// - /// Limits the list of properties to populate to just the indicated list. - /// - /// The properties of the object to populate. - /// ILink<TResult>. - ILink WithProperties(params string[] propertiesToPopulate); + /// The properties to omit. + /// ILink<TResult>. + ILink ExceptProperties(params string[] propertiesToOmit); - /// - /// Excludes the properties from the list of what will be populated in the object. - /// - /// The properties to omit. - /// ILink<TResult>. - ILink ExceptProperties(params string[] propertiesToOmit); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The constructor signature. + ILink WithConstructor(params Type[] constructorSignature); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The constructor signature. - ILink WithConstructor(params Type[] constructorSignature); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// The type of the 5th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// The type of the 5th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// The type of the 5th constructor parameter. + /// The type of the 6th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// The type of the 5th constructor parameter. - /// The type of the 6th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// The type of the 5th constructor parameter. + /// The type of the 6th constructor parameter. + /// The type of the 7th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// The type of the 5th constructor parameter. - /// The type of the 6th constructor parameter. - /// The type of the 7th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// The type of the 5th constructor parameter. + /// The type of the 6th constructor parameter. + /// The type of the 7th constructor parameter. + /// The type of the 8th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// The type of the 5th constructor parameter. - /// The type of the 6th constructor parameter. - /// The type of the 7th constructor parameter. - /// The type of the 8th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// The type of the 5th constructor parameter. + /// The type of the 6th constructor parameter. + /// The type of the 7th constructor parameter. + /// The type of the 8th constructor parameter. + /// The type of the 9th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// The type of the 5th constructor parameter. - /// The type of the 6th constructor parameter. - /// The type of the 7th constructor parameter. - /// The type of the 8th constructor parameter. - /// The type of the 9th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the 1st constructor parameter. + /// The type of the 2nd constructor parameter. + /// The type of the 3rd constructor parameter. + /// The type of the 4th constructor parameter. + /// The type of the 5th constructor parameter. + /// The type of the 6th constructor parameter. + /// The type of the 7th constructor parameter. + /// The type of the 8th constructor parameter. + /// The type of the 9th constructor parameter. + /// The type of the 10th constructor parameter. + /// ILink<TResult>. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + ILink WithConstructor(); - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the 1st constructor parameter. - /// The type of the 2nd constructor parameter. - /// The type of the 3rd constructor parameter. - /// The type of the 4th constructor parameter. - /// The type of the 5th constructor parameter. - /// The type of the 6th constructor parameter. - /// The type of the 7th constructor parameter. - /// The type of the 8th constructor parameter. - /// The type of the 9th constructor parameter. - /// The type of the 10th constructor parameter. - /// ILink<TResult>. - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - ILink WithConstructor(); - } + /// + /// Limits the list of properties to populate to just the indicated list. + /// + /// The properties of the object to populate. + /// ILink<TResult>. + ILink WithProperties(params string[] propertiesToPopulate); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/ILink`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/ILink`1.cs index 9154bf094..a70e6b090 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/ILink`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/ILink`1.cs @@ -2,61 +2,60 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This is implemented by materializers and appenders that return a value. +/// + +public interface ILink { /// - /// This is implemented by materializers and appenders that return a value. + /// Occurs when an execution token has been prepared. + /// + /// This is mostly used by appenders to override command behavior. + [EditorBrowsable(EditorBrowsableState.Never)] + event EventHandler? ExecutionTokenPrepared; + + /// + /// Occurs when an execution token is about to be prepared. /// + /// This is mostly used by appenders to override SQL generation. + [EditorBrowsable(EditorBrowsableState.Never)] + event EventHandler? ExecutionTokenPreparing; - public interface ILink - { - /// - /// Occurs when an execution token has been prepared. - /// - /// This is mostly used by appenders to override command behavior. - [EditorBrowsable(EditorBrowsableState.Never)] - event EventHandler? ExecutionTokenPrepared; - - /// - /// Occurs when an execution token is about to be prepared. - /// - /// This is mostly used by appenders to override SQL generation. - [EditorBrowsable(EditorBrowsableState.Never)] - event EventHandler? ExecutionTokenPreparing; - - /// - /// Gets the data source that is associated with this materializer or appender. - /// - /// The data source. - /// This is only used for cache operations - [EditorBrowsable(EditorBrowsableState.Never)] - IDataSource DataSource { get; } - - /// - /// Returns command text (usually SQL) without executing it. - /// - /// - string? CommandText(); - - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - TResult Execute(object? state = null); - - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// - Task ExecuteAsync(object? state = null); - - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); - } + /// + /// Gets the data source that is associated with this materializer or appender. + /// + /// The data source. + /// This is only used for cache operations + [EditorBrowsable(EditorBrowsableState.Never)] + IDataSource DataSource { get; } + + /// + /// Returns command text (usually SQL) without executing it. + /// + /// + string? CommandText(); + + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + TResult Execute(object? state = null); + + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// + Task ExecuteAsync(object? state = null); + + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/InsertOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/InsertOptions.cs index 40d494f38..e1c823784 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/InsertOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/InsertOptions.cs @@ -1,29 +1,28 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Controls what happens when performing a model-based insert +/// +[Flags] +public enum InsertOptions { /// - /// Controls what happens when performing a model-based insert + /// Use the default behavior. /// - [Flags] - public enum InsertOptions - { - /// - /// Use the default behavior. - /// - None = 0, + None = 0, - /// - /// Override the identity/auto-number column. - /// - /// This may require elevated privileges. - IdentityInsert = 4, + /// + /// Override the identity/auto-number column. + /// + /// This may require elevated privileges. + IdentityInsert = 4, - /* - * Might need this for PostgreSQL - /// - /// Do not reset the identity/auto-number column after performing an identity insert. - /// - /// Use this when performing a series of identity inserts to improve performance. Then invoke ResetIdentity on the DataSource. This is a no-op when resetting the identity column is not necessary (Access, SQL Server, SQLite). - DoNotResetIdentityColumn = 8 - */ - } -} \ No newline at end of file + /* + * Might need this for PostgreSQL + /// + /// Do not reset the identity/auto-number column after performing an identity insert. + /// + /// Use this when performing a series of identity inserts to improve performance. Then invoke ResetIdentity on the DataSource. This is a no-op when resetting the identity column is not necessary (Access, SQL Server, SQLite). + DoNotResetIdentityColumn = 8 + */ +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/JoinOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/JoinOptions.cs index ad5b5c5c8..8671711dd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/JoinOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/JoinOptions.cs @@ -1,30 +1,29 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Enum JoinOptions +/// +[Flags] +public enum JoinOptions { /// - /// Enum JoinOptions + /// The default behavior is to assign the child object to the first matching parent object. If there are no matches, an error is thrown. /// - [Flags] - public enum JoinOptions - { - /// - /// The default behavior is to assign the child object to the first matching parent object. If there are no matches, an error is thrown. - /// - None = 0, + None = 0, - /// - /// Continues searching when the first match is found, possibly assigning one the detail record to multiple parent records. - /// - MultipleParents = 1, + /// + /// Continues searching when the first match is found, possibly assigning one the detail record to multiple parent records. + /// + MultipleParents = 1, - /// - /// If there are unmatchable child records, silently discard them instead of throwing an exception. - /// - IgnoreUnmatchedChildren = 2, + /// + /// If there are unmatchable child records, silently discard them instead of throwing an exception. + /// + IgnoreUnmatchedChildren = 2, - /// - /// Perform the join in parallel. - /// - /// Lock overhead may make this slower than the normal mode. This relies on PLINQ, which may decide to not go parallel for small collections. - Parallel = 4, - } + /// + /// Perform the join in parallel. + /// + /// Lock overhead may make this slower than the normal mode. This relies on PLINQ, which may decide to not go parallel for small collections. + Parallel = 4, } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/LimitOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/LimitOptions.cs index 4f41011f4..a1810d80a 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/LimitOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/LimitOptions.cs @@ -1,85 +1,84 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Types of limits that can be applied to a table, view, or table-value function query. +/// +/// Databases are expected to provide their own enumeration that represents a subset of these options. +[Flags] +public enum LimitOptions { /// - /// Types of limits that can be applied to a table, view, or table-value function query. + /// No limits were applied. /// - /// Databases are expected to provide their own enumeration that represents a subset of these options. - [Flags] - public enum LimitOptions - { - /// - /// No limits were applied. - /// - None = 0, + None = 0, - /// - /// Returns the indicated number of rows with optional offset - /// - Rows = 1, + /// + /// Returns the indicated number of rows with optional offset + /// + Rows = 1, - /// - /// Returns the indicated percentage of rows. May be applied to TableSample - /// - Percentage = 2, + /// + /// Returns the indicated percentage of rows. May be applied to TableSample + /// + Percentage = 2, - /// - /// Adds WithTies behavior to Rows or Percentage - /// - WithTies = 4, + /// + /// Adds WithTies behavior to Rows or Percentage + /// + WithTies = 4, - /// - /// Returns the top N rows. When there is a tie for the Nth record, this will cause it to be returned. - /// - RowsWithTies = Rows | WithTies, + /// + /// Returns the top N rows. When there is a tie for the Nth record, this will cause it to be returned. + /// + RowsWithTies = Rows | WithTies, - /// - /// Returns the top N percentage of rows. When there is a tie for the Nth record, this will cause it to be returned. - /// - PercentageWithTies = Percentage | WithTies, + /// + /// Returns the top N percentage of rows. When there is a tie for the Nth record, this will cause it to be returned. + /// + PercentageWithTies = Percentage | WithTies, - /// - /// Randomly select a set of rows. Combine this with Rows or Percentage and optionally a Table Sample algorithm. - /// - RandomSample = 8, + /// + /// Randomly select a set of rows. Combine this with Rows or Percentage and optionally a Table Sample algorithm. + /// + RandomSample = 8, - /// - /// Randomly sample the indicated number of rows - /// - RandomSampleRows = RandomSample | Rows, + /// + /// Randomly sample the indicated number of rows + /// + RandomSampleRows = RandomSample | Rows, - /// - /// Randomly sample the indicated percentage of rows - /// - RandomSamplePercentage = RandomSample | Percentage, + /// + /// Randomly sample the indicated percentage of rows + /// + RandomSamplePercentage = RandomSample | Percentage, - /// - /// Adds the Table Sample System algorithm to a random sample. - /// - TableSampleSystem = 16, + /// + /// Adds the Table Sample System algorithm to a random sample. + /// + TableSampleSystem = 16, - /// - /// Randomly sample N rows using the Table Sample System algorithm. - /// - TableSampleSystemRows = RandomSample | TableSampleSystem | Rows, + /// + /// Randomly sample N rows using the Table Sample System algorithm. + /// + TableSampleSystemRows = RandomSample | TableSampleSystem | Rows, - /// - /// Randomly sample N percentage of rows using the Table Sample System algorithm. - /// - TableSampleSystemPercentage = RandomSample | TableSampleSystem | Percentage, + /// + /// Randomly sample N percentage of rows using the Table Sample System algorithm. + /// + TableSampleSystemPercentage = RandomSample | TableSampleSystem | Percentage, - /// - /// Adds the Table Sample Bernoulli algorithm behavior to a random sample. - /// - TableSampleBernoulli = 32, + /// + /// Adds the Table Sample Bernoulli algorithm behavior to a random sample. + /// + TableSampleBernoulli = 32, - /// - /// Randomly sample N rows using the Table Sample Bernoulli algorithm. - /// - TableSampleBernoulliRows = RandomSample | TableSampleBernoulli | Rows, + /// + /// Randomly sample N rows using the Table Sample Bernoulli algorithm. + /// + TableSampleBernoulliRows = RandomSample | TableSampleBernoulli | Rows, - /// - /// Randomly sample N percentage of rows using the Table Sample Bernoulli algorithm. - /// - TableSampleBernoulliPercentage = RandomSample | TableSampleBernoulli | Percentage, - } + /// + /// Randomly sample N percentage of rows using the Table Sample Bernoulli algorithm. + /// + TableSampleBernoulliPercentage = RandomSample | TableSampleBernoulli | Percentage, } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/ListOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/ListOptions.cs index 86d8588bf..08dd8b867 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/ListOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/ListOptions.cs @@ -1,32 +1,31 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Indicates how the list will be generated from a result set. +/// +[SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags")] +[Flags] +public enum ListOptions { /// - /// Indicates how the list will be generated from a result set. + /// An error will occur unless exactly one column is returned. /// - [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags")] - [Flags] - public enum ListOptions - { - /// - /// An error will occur unless exactly one column is returned. - /// - None = 0, + None = 0, - /// - /// Null values will be removed from the list. - /// - DiscardNulls = 1, + /// + /// Null values will be removed from the list. + /// + DiscardNulls = 1, - /// - /// If extra columns are returned, all but the first will be ignored. - /// - IgnoreExtraColumns = 2, + /// + /// If extra columns are returned, all but the first will be ignored. + /// + IgnoreExtraColumns = 2, - /// - /// All columns will be incorporated into the result set. Values are read left to right, then top to bottom. - /// - FlattenExtraColumns = 2 + 4 - } + /// + /// All columns will be incorporated into the result set. Values are read left to right, then top to bottom. + /// + FlattenExtraColumns = 2 + 4 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/MappingException.cs b/Tortuga.Chain/Tortuga.Chain.Core/MappingException.cs index dc5c98ceb..e3cfff008 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/MappingException.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/MappingException.cs @@ -1,48 +1,47 @@ using System.Runtime.Serialization; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This exception occurs when there is a mismatch between the database schema and the object model. +/// +/// +[Serializable] +public class MappingException : DataException { /// - /// This exception occurs when there is a mismatch between the database schema and the object model. + /// Initializes a new instance of the class. /// - /// - [Serializable] - public class MappingException : DataException + public MappingException() { - /// - /// Initializes a new instance of the class. - /// - public MappingException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public MappingException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public MappingException(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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. - public MappingException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// 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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. + public MappingException(string message, Exception? innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The data necessary to serialize or deserialize an object. - /// Description of the source and destination of the specified serialized stream. - protected MappingException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The data necessary to serialize or deserialize an object. + /// Description of the source and destination of the specified serialized stream. + protected MappingException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`2.cs index dfdacd0d0..3408d2bac 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`2.cs @@ -2,78 +2,77 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This Materializer captures output parameters and returns them as a dictionary. +/// +public class AsOutputsMaterializer : Materializer> + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// This Materializer captures output parameters and returns them as a dictionary. + /// Initializes a new instance of the class. /// - public class AsOutputsMaterializer : Materializer> - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - public AsOutputsMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { } + /// The associated operation. + public AsOutputsMaterializer(DbCommandBuilder commandBuilder) +: base(commandBuilder) + { } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// IReadOnlyList<System.String>. - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - public override IReadOnlyList DesiredColumns() => NoColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// IReadOnlyList<System.String>. + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + public override IReadOnlyList DesiredColumns() => NoColumns; - /// - /// Execute the operation synchronously. - /// - /// The state. - /// Dictionary<System.String, System.Nullable<System.Object>>. - public override Dictionary Execute(object? state = null) - { - var commandToken = Prepare(); + /// + /// Execute the operation synchronously. + /// + /// The state. + /// Dictionary<System.String, System.Nullable<System.Object>>. + public override Dictionary Execute(object? state = null) + { + var commandToken = Prepare(); - commandToken.Execute(cmd => cmd.ExecuteNonQuery(), state); + commandToken.Execute(cmd => cmd.ExecuteNonQuery(), state); - return CaptureOutputParameters(commandToken); - } + return CaptureOutputParameters(commandToken); + } - internal static Dictionary CaptureOutputParameters(CommandExecutionToken commandToken) - { - var result = new Dictionary(); - foreach (var param in commandToken.Parameters - .Where(p => p.Direction == ParameterDirection.Output || p.Direction == ParameterDirection.InputOutput)) - { - var name = param.ParameterName.Replace("@", "", StringComparison.OrdinalIgnoreCase); //TODO: Generalize this for all databases. - //var name = CommandBuilder.DataSource.DatabaseMetadata.CleanParameterName(param.ParameterName); + /// + /// execute as an asynchronous operation. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task<Dictionary<System.String, System.Nullable<System.Object>>>. + public async override Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var commandToken = Prepare(); - var value = param.Value == DBNull.Value ? null : param.Value; + await commandToken.ExecuteAsync(async cmd => + { + return await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + }, cancellationToken, state).ConfigureAwait(false); - result[name] = value; - } - if (result.Count == 0) - throw new MappingException("No output parameters found."); - return result; - } + return CaptureOutputParameters(commandToken); + } - /// - /// execute as an asynchronous operation. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task<Dictionary<System.String, System.Nullable<System.Object>>>. - public async override Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + internal static Dictionary CaptureOutputParameters(CommandExecutionToken commandToken) + { + var result = new Dictionary(); + foreach (var param in commandToken.Parameters + .Where(p => p.Direction == ParameterDirection.Output || p.Direction == ParameterDirection.InputOutput)) { - var commandToken = Prepare(); + var name = param.ParameterName.Replace("@", "", StringComparison.OrdinalIgnoreCase); //TODO: Generalize this for all databases. + //var name = CommandBuilder.DataSource.DatabaseMetadata.CleanParameterName(param.ParameterName); - await commandToken.ExecuteAsync(async cmd => - { - return await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); - }, cancellationToken, state).ConfigureAwait(false); + var value = param.Value == DBNull.Value ? null : param.Value; - return CaptureOutputParameters(commandToken); + result[name] = value; } + if (result.Count == 0) + throw new MappingException("No output parameters found."); + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`3.cs index 00d2fdee6..297b5b982 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/AsOutputsMaterializer`3.cs @@ -2,70 +2,69 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This Materializer captures output parameters and returns them as an object. +/// +public class AsOutputsMaterializer : Materializer + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class, new() { /// - /// This Materializer captures output parameters and returns them as an object. + /// Initializes a new instance of the class. /// - public class AsOutputsMaterializer : Materializer - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class, new() + /// The associated operation. + public AsOutputsMaterializer(DbCommandBuilder commandBuilder) +: base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - public AsOutputsMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { - } + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// IReadOnlyList<System.String>. - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - public override IReadOnlyList DesiredColumns() => NoColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// IReadOnlyList<System.String>. + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + public override IReadOnlyList DesiredColumns() => NoColumns; - /// - /// Execute the operation synchronously. - /// - /// The state. - /// Dictionary<System.String, System.Nullable<System.Object>>. - public override TObject Execute(object? state = null) - { - var commandToken = Prepare(); + /// + /// Execute the operation synchronously. + /// + /// The state. + /// Dictionary<System.String, System.Nullable<System.Object>>. + public override TObject Execute(object? state = null) + { + var commandToken = Prepare(); - commandToken.Execute(cmd => cmd.ExecuteNonQuery(), state); + commandToken.Execute(cmd => cmd.ExecuteNonQuery(), state); - return CaptureOutputParameters(commandToken); - } + return CaptureOutputParameters(commandToken); + } - static TObject CaptureOutputParameters(CommandExecutionToken commandToken) - { - var result = AsOutputsMaterializer.CaptureOutputParameters(commandToken); - var objectResult = new TObject(); - MaterializerUtilities.PopulateComplexObject(result, objectResult, null); - return objectResult; - } + /// + /// execute as an asynchronous operation. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task<Dictionary<System.String, System.Nullable<System.Object>>>. + public async override Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var commandToken = Prepare(); - /// - /// execute as an asynchronous operation. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task<Dictionary<System.String, System.Nullable<System.Object>>>. - public async override Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + await commandToken.ExecuteAsync(async cmd => { - var commandToken = Prepare(); + return await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + }, cancellationToken, state).ConfigureAwait(false); - await commandToken.ExecuteAsync(async cmd => - { - return await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); - }, cancellationToken, state).ConfigureAwait(false); + return CaptureOutputParameters(commandToken); + } - return CaptureOutputParameters(commandToken); - } + TObject CaptureOutputParameters(CommandExecutionToken commandToken) + { + var result = AsOutputsMaterializer.CaptureOutputParameters(commandToken); + var objectResult = new TObject(); + MaterializerUtilities.PopulateComplexObject(result, objectResult, null, Converter); + return objectResult; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/ConstructibleMaterializer`4.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/ConstructibleMaterializer`4.cs index cba41e6ea..255156471 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/ConstructibleMaterializer`4.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/ConstructibleMaterializer`4.cs @@ -2,368 +2,367 @@ using Tortuga.Anchor.Metadata; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Class ConstructibleMaterializer. +/// +/// The type of the t command. +/// The type of the t parameter. +/// The type of the result. This may be a collection of TObject. +/// The type of the object that will be returned. +/// +/// +public abstract class ConstructibleMaterializer : Materializer, IConstructibleMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Class ConstructibleMaterializer. + /// Initializes a new instance of the class. /// - /// The type of the t command. - /// The type of the t parameter. - /// The type of the result. This may be a collection of TObject. - /// The type of the object that will be returned. - /// - /// - public abstract class ConstructibleMaterializer : Materializer, IConstructibleMaterializer - where TCommand : DbCommand - where TParameter : DbParameter + /// The associated operation. + protected ConstructibleMaterializer(DbCommandBuilder commandBuilder) : base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - protected ConstructibleMaterializer(DbCommandBuilder commandBuilder) : base(commandBuilder) - { - ObjectMetadata = MetadataCache.GetMetadata(typeof(TObject)); - } + ObjectMetadata = MetadataCache.GetMetadata(typeof(TObject)); + } - /// - /// Sets the constructor using a signature. - /// - /// The constructor signature. - /// Cannot find a matching constructor for the desired type - protected void SetConstructor(IReadOnlyList? signature) - { - if (signature == null) - { - Constructor = null; - } - else - { - var constructor = ObjectMetadata.Constructors.Find(signature); - if (constructor == null) - { - var types = string.Join(", ", signature.Select(t => t.Name)); - throw new MappingException($"Cannot find a constructor on {typeof(Type).Name} with the types [{types}]"); - } - Constructor = constructor; - } - } + /// + /// Gets or sets the data reader constructor. + /// + /// The data reader constructor. + protected ConstructorMetadata? Constructor { get; set; } + + /// + /// Columns to ignore when generating the list of desired columns. + /// + /// The excluded columns. + protected IReadOnlyList? ExcludedColumns { get; private set; } - /// - /// Materializers use this to pick a constructor. - /// - /// - /// - protected ConstructorMetadata InferConstructor() + /// + /// Only include the indicated columns when generating the list of desired columns. + /// + /// The included columns. + protected IReadOnlyList? IncludedColumns { get; private set; } + + /// + /// Gets or sets the TObject metadata. + /// + /// The object metadata. + protected ClassMetadata ObjectMetadata { get; } + + /// + /// Returns the list of columns the result materializer would like to have. + /// + /// IReadOnlyList<System.String>. + /// + /// Cannot find a constructor on {desiredType.Name} with the types [{types}] + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which + /// columns to return. If NoColumns is returned, the command builder should omit the + /// SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() + { + if (Constructor == null && !ObjectMetadata.Constructors.HasDefaultConstructor) { - //This is here to make the error message more accurate. - if (ObjectMetadata.Constructors.Count == 0) - throw new MappingException($"Type {typeof(TObject).Name} has does not have any constructors."); - - //For inference, we're looking for non-default constructors. - var constructors = ObjectMetadata.Constructors.Where(x => x.Signature.Length > 0).ToList(); - if (constructors.Count == 0) - throw new MappingException($"Type {typeof(TObject).Name} has does not have any non-default constructors."); - if (constructors.Count > 1) - throw new MappingException($"Type {typeof(TObject).Name} has more than one non-default constructor. Please use the WithConstructor method to specify which one to use."); - return constructors.Single(); + Constructor = InferConstructor(); } - /// - /// Gets or sets the data reader constructor. - /// - /// The data reader constructor. - protected ConstructorMetadata? Constructor { get; set; } - - /// - /// Columns to ignore when generating the list of desired columns. - /// - /// The excluded columns. - protected IReadOnlyList? ExcludedColumns { get; private set; } - - /// - /// Only include the indicated columns when generating the list of desired columns. - /// - /// The included columns. - protected IReadOnlyList? IncludedColumns { get; private set; } - - /// - /// Gets or sets the TObject metadata. - /// - /// The object metadata. - protected ClassMetadata ObjectMetadata { get; } - - /// - /// Returns the list of columns the result materializer would like to have. - /// - /// IReadOnlyList<System.String>. - /// - /// Cannot find a constructor on {desiredType.Name} with the types [{types}] - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which - /// columns to return. If NoColumns is returned, the command builder should omit the - /// SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() + if (Constructor == null) { - if (Constructor == null && !ObjectMetadata.Constructors.HasDefaultConstructor) - { - Constructor = InferConstructor(); - } + IReadOnlyList result = ObjectMetadata.ColumnsFor; - if (Constructor == null) - { - IReadOnlyList result = ObjectMetadata.ColumnsFor; + if (result.Count == 0) + throw new MappingException($"Type {typeof(TObject).Name} has no writable properties. Please use the InferConstructor option or the WithConstructor method."); - if (result.Count == 0) - throw new MappingException($"Type {typeof(TObject).Name} has no writable properties. Please use the InferConstructor option or the WithConstructor method."); + if (IncludedColumns != null && ExcludedColumns != null) + throw new InvalidOperationException("Cannot specify both included and excluded columns/properties."); - if (IncludedColumns != null && ExcludedColumns != null) - throw new InvalidOperationException("Cannot specify both included and excluded columns/properties."); + if (IncludedColumns != null) + return IncludedColumns; - if (IncludedColumns != null) - return IncludedColumns; + if (ExcludedColumns != null) + result = result.Where(x => !ExcludedColumns.Contains(x)).ToList(); + return result; + } - if (ExcludedColumns != null) - result = result.Where(x => !ExcludedColumns.Contains(x)).ToList(); - return result; - } + if (IncludedColumns != null) + throw new NotImplementedException("Cannot specify included columns/properties with constructors. See #295"); - if (IncludedColumns != null) - throw new NotImplementedException("Cannot specify included columns/properties with constructors. See #295"); + if (ExcludedColumns != null) + throw new InvalidOperationException("Cannot specify excluded columns/properties with constructors."); - if (ExcludedColumns != null) - throw new InvalidOperationException("Cannot specify excluded columns/properties with constructors."); + return Constructor.ParameterNames; + } - return Constructor.ParameterNames; - } + /// + /// Excludes the properties from the list of what will be populated in the object. + /// + /// The properties to omit. + public ILink ExceptProperties(params string[] propertiesToOmit) + { + if (propertiesToOmit == null || propertiesToOmit.Length == 0) + return this; - /// - /// Excludes the properties from the list of what will be populated in the object. - /// - /// The properties to omit. - public ILink ExceptProperties(params string[] propertiesToOmit) + var result = new List(propertiesToOmit.Length); + var meta = MetadataCache.GetMetadata(); + foreach (var propertyName in propertiesToOmit) { - if (propertiesToOmit == null || propertiesToOmit.Length == 0) - return this; - - var result = new List(propertiesToOmit.Length); - var meta = MetadataCache.GetMetadata(); - foreach (var propertyName in propertiesToOmit) + if (meta.Properties.TryGetValue(propertyName, out var property)) { - if (meta.Properties.TryGetValue(propertyName, out var property)) - { - if (property.MappedColumnName != null) - result.Add(property.MappedColumnName); - } + if (property.MappedColumnName != null) + result.Add(property.MappedColumnName); } - - ExcludedColumns = result; - return this; } - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The constructor signature. - /// ILink<TResult>. + ExcludedColumns = result; + return this; + } - public ILink WithConstructor(params Type[] constructorSignature) - { - SetConstructor(constructorSignature); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The constructor signature. + /// ILink<TResult>. - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// ILink<TResult>. + public ILink WithConstructor(params Type[] constructorSignature) + { + SetConstructor(constructorSignature); + return this; + } - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1) }); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// ILink<TResult>. - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// ILink<TResult>. + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1) }); + return this; + } - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2) }); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// ILink<TResult>. - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// ILink<TResult>. + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2) }); + return this; + } - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3) }); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// ILink<TResult>. - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// ILink<TResult>. + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3) }); + return this; + } - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// ILink<TResult>. - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// The type of the t5. - /// ILink<TResult>. - - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }); - return this; - } + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }); + return this; + } - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// The type of the t5. - /// The type of the t6. - /// ILink<TResult>. - - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) }); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// The type of the t5. + /// ILink<TResult>. + + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }); + return this; + } - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// The type of the t5. - /// The type of the t6. - /// The type of the t7. - /// ILink<TResult>. - - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7) }); - return this; - } + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// The type of the t5. + /// The type of the t6. + /// ILink<TResult>. + + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) }); + return this; + } - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// The type of the t5. - /// The type of the t6. - /// The type of the t7. - /// The type of the t8. - /// ILink<TResult>. - - public ILink WithConstructor() - { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8) }); + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// The type of the t5. + /// The type of the t6. + /// The type of the t7. + /// ILink<TResult>. + + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7) }); + return this; + } + + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// The type of the t5. + /// The type of the t6. + /// The type of the t7. + /// The type of the t8. + /// ILink<TResult>. + + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8) }); + return this; + } + + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// The type of the t5. + /// The type of the t6. + /// The type of the t7. + /// The type of the t8. + /// The type of the t9. + /// ILink<TResult>. + + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9) }); + return this; + } + + /// + /// Appends the indicated constructor onto the materializer. + /// + /// The type of the t1. + /// The type of the t2. + /// The type of the t3. + /// The type of the t4. + /// The type of the t5. + /// The type of the t6. + /// The type of the t7. + /// The type of the t8. + /// The type of the t9. + /// The type of the T10. + /// ILink<TResult>. + + public ILink WithConstructor() + { + SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10) }); + return this; + } + + /// + /// Limits the list of properties to populate to just the indicated list. + /// + /// The properties of the object to populate. + /// ILink<TResult>. + public ILink WithProperties(params string[] propertiesToPopulate) + { + if (propertiesToPopulate == null || propertiesToPopulate.Length == 0) return this; - } - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// The type of the t5. - /// The type of the t6. - /// The type of the t7. - /// The type of the t8. - /// The type of the t9. - /// ILink<TResult>. - - public ILink WithConstructor() + var result = new List(propertiesToPopulate.Length); + var meta = MetadataCache.GetMetadata(); + foreach (var propertyName in propertiesToPopulate) { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9) }); - return this; + if (meta.Properties.TryGetValue(propertyName, out var property)) + { + if (property.MappedColumnName != null) + result.Add(property.MappedColumnName); + } } - /// - /// Appends the indicated constructor onto the materializer. - /// - /// The type of the t1. - /// The type of the t2. - /// The type of the t3. - /// The type of the t4. - /// The type of the t5. - /// The type of the t6. - /// The type of the t7. - /// The type of the t8. - /// The type of the t9. - /// The type of the T10. - /// ILink<TResult>. - - public ILink WithConstructor() + IncludedColumns = result; + return this; + } + + /// + /// Materializers use this to pick a constructor. + /// + /// + /// + protected ConstructorMetadata InferConstructor() + { + //This is here to make the error message more accurate. + if (ObjectMetadata.Constructors.Count == 0) + throw new MappingException($"Type {typeof(TObject).Name} has does not have any constructors."); + + //For inference, we're looking for non-default constructors. + var constructors = ObjectMetadata.Constructors.Where(x => x.Signature.Length > 0).ToList(); + if (constructors.Count == 0) + throw new MappingException($"Type {typeof(TObject).Name} has does not have any non-default constructors."); + if (constructors.Count > 1) + throw new MappingException($"Type {typeof(TObject).Name} has more than one non-default constructor. Please use the WithConstructor method to specify which one to use."); + return constructors.Single(); + } + + /// + /// Sets the constructor using a signature. + /// + /// The constructor signature. + /// Cannot find a matching constructor for the desired type + protected void SetConstructor(IReadOnlyList? signature) + { + if (signature == null) { - SetConstructor(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10) }); - return this; + Constructor = null; } - - /// - /// Limits the list of properties to populate to just the indicated list. - /// - /// The properties of the object to populate. - /// ILink<TResult>. - public ILink WithProperties(params string[] propertiesToPopulate) + else { - if (propertiesToPopulate == null || propertiesToPopulate.Length == 0) - return this; - - var result = new List(propertiesToPopulate.Length); - var meta = MetadataCache.GetMetadata(); - foreach (var propertyName in propertiesToPopulate) + var constructor = ObjectMetadata.Constructors.Find(signature); + if (constructor == null) { - if (meta.Properties.TryGetValue(propertyName, out var property)) - { - if (property.MappedColumnName != null) - result.Add(property.MappedColumnName); - } + var types = string.Join(", ", signature.Select(t => t.Name)); + throw new MappingException($"Cannot find a constructor on {typeof(Type).Name} with the types [{types}]"); } - - IncludedColumns = result; - return this; + Constructor = constructor; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`1.cs index 30d3b2d32..5c560a485 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`1.cs @@ -1,22 +1,21 @@ using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal class MappedProperty where TTarget : class { - internal class MappedProperty where TTarget : class + public MappedProperty(string mappedColumnName, PropertyMetadata propertyMetadata) { - public MappedProperty(string mappedColumnName, PropertyMetadata propertyMetadata) - { - MappedColumnName = mappedColumnName; - PropertyMetadata = propertyMetadata; - } + MappedColumnName = mappedColumnName; + PropertyMetadata = propertyMetadata; + } - public string MappedColumnName { get; } + public string MappedColumnName { get; } - public PropertyMetadata PropertyMetadata { get; } + public PropertyMetadata PropertyMetadata { get; } - public virtual void InvokeSet(TTarget target, object? value) - { - PropertyMetadata.InvokeSet(target, value); - } + public virtual void InvokeSet(TTarget target, object? value) + { + PropertyMetadata.InvokeSet(target, value); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`2.cs index 6ca8e696e..4ee680c05 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MappedProperty`2.cs @@ -1,26 +1,25 @@ using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// The purpose of this class +/// +/// The type of the target. +/// The type of the property. +internal class MappedProperty : MappedProperty + where TTarget : class { - /// - /// The purpose of this class - /// - /// The type of the target. - /// The type of the property. - internal class MappedProperty : MappedProperty - where TTarget : class - { - readonly Action m_DelegateSetter; + readonly Action m_DelegateSetter; - public MappedProperty(string mappedColumnName, PropertyMetadata propertyMetadata) : base(mappedColumnName, propertyMetadata) - { - m_DelegateSetter = PropertyMetadata.CreateDelegateSetter(); - } + public MappedProperty(string mappedColumnName, PropertyMetadata propertyMetadata) : base(mappedColumnName, propertyMetadata) + { + m_DelegateSetter = PropertyMetadata.CreateDelegateSetter(); + } #nullable disable - public override void InvokeSet(TTarget target, object value) => m_DelegateSetter(target, (TProperty)value); + public override void InvokeSet(TTarget target, object value) => m_DelegateSetter(target, (TProperty)value); #nullable restore - } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer.cs index f4daa2a1e..af919cf57 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer.cs @@ -2,74 +2,73 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.Core; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This is the root base class for materializers. It is used when we need to strip away the generic type arguments. +/// +public abstract class Materializer { /// - /// This is the root base class for materializers. It is used when we need to strip away the generic type arguments. + /// Return all columns. /// - public abstract class Materializer - { - /// - /// Return all columns. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly IReadOnlyList AllColumns = new ReadOnlyCollection(new List()); + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly IReadOnlyList AllColumns = new ReadOnlyCollection(new List()); - /// - /// The automatically select desired columns. If there are primary key column(s), return them. Otherwise look for an identity column. If that is missing too, raise an exception. - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly IReadOnlyList AutoSelectDesiredColumns = new ReadOnlyCollection(new List()); + /// + /// The automatically select desired columns. If there are primary key column(s), return them. Otherwise look for an identity column. If that is missing too, raise an exception. + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly IReadOnlyList AutoSelectDesiredColumns = new ReadOnlyCollection(new List()); - /// - /// Return no columns. Used when the result of the operation is not desired (e.g. insert/update). - /// - [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly IReadOnlyList NoColumns = new ReadOnlyCollection(new List()); + /// + /// Return no columns. Used when the result of the operation is not desired (e.g. insert/update). + /// + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly IReadOnlyList NoColumns = new ReadOnlyCollection(new List()); - ///// - ///// Indicates that AdvancedColumns should be used instead of DesiredColumns - ///// - //public static readonly IReadOnlyList UseAdvancedColumns = new ReadOnlyCollection(new List()); + ///// + ///// Indicates that AdvancedColumns should be used instead of DesiredColumns + ///// + //public static readonly IReadOnlyList UseAdvancedColumns = new ReadOnlyCollection(new List()); - /// - /// Occurs when an execution token has been prepared. - /// - /// This is mostly used by appenders to override command behavior. - public event EventHandler? ExecutionTokenPrepared; + /// + /// Occurs when an execution token has been prepared. + /// + /// This is mostly used by appenders to override command behavior. + public event EventHandler? ExecutionTokenPrepared; - /// - /// Occurs when execution token is about to be been prepared. - /// - /// This is mostly used by appenders to override SQL generation. - public event EventHandler? ExecutionTokenPreparing; + /// + /// Occurs when execution token is about to be been prepared. + /// + /// This is mostly used by appenders to override SQL generation. + public event EventHandler? ExecutionTokenPreparing; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// IReadOnlyList<System.String>. - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - public virtual IReadOnlyList DesiredColumns() - { - return AutoSelectDesiredColumns; - } + /// + /// Returns the list of columns the materializer would like to have. + /// + /// IReadOnlyList<System.String>. + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + public virtual IReadOnlyList DesiredColumns() + { + return AutoSelectDesiredColumns; + } - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) - { - ExecutionTokenPrepared?.Invoke(this, e); - } + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) + { + ExecutionTokenPrepared?.Invoke(this, e); + } - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) - { - ExecutionTokenPreparing?.Invoke(this, e); - } + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected void OnExecutionTokenPreparing(ExecutionTokenPreparingEventArgs e) + { + ExecutionTokenPreparing?.Invoke(this, e); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MaterializerUtilities.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MaterializerUtilities.cs index 37b498a0c..52e733fa4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MaterializerUtilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MaterializerUtilities.cs @@ -1,9 +1,6 @@ using System.ComponentModel; using System.Data.Common; using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection; -using System.Xml.Linq; using Tortuga.Anchor.Metadata; using Tortuga.Chain.Core; using Tortuga.Chain.Metadata; @@ -19,88 +16,88 @@ public static class MaterializerUtilities static readonly Type[] s_EmptyTypeList = Array.Empty(); /// - /// Checks the update row count. + /// Checks the delete row count. /// /// /// The execution token. - /// The update options. + /// The delete options. /// The expected row count. /// The execution token with an attached event handler. - public static T CheckUpdateRowCount(this T executionToken, UpdateOptions updateOptions, int? expectedRowCount) where T : ExecutionToken + public static T CheckDeleteRowCount(this T executionToken, DeleteOptions deleteOptions, int? expectedRowCount) where T : ExecutionToken { if (executionToken == null) throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (expectedRowCount.HasValue && !updateOptions.HasFlag(UpdateOptions.IgnoreRowsAffected)) - executionToken.CommandExecuted += (s, e) => CheckUpdateRowCount(s, e, expectedRowCount.Value); + if (expectedRowCount.HasValue && deleteOptions.HasFlag(DeleteOptions.CheckRowsAffected)) + executionToken.CommandExecuted += (s, e) => CheckDeleteRowCount(s, e, expectedRowCount.Value); return executionToken; } /// - /// Checks the update row count. + /// Checks the delete row count. /// /// /// The execution token. - /// The update options. + /// The delete options. /// The execution token with an attached event handler. - public static T CheckUpdateRowCount(this T executionToken, UpdateOptions updateOptions) where T : ExecutionToken + public static T CheckDeleteRowCount(this T executionToken, DeleteOptions deleteOptions) where T : ExecutionToken { if (executionToken == null) throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (!updateOptions.HasFlag(UpdateOptions.IgnoreRowsAffected)) - executionToken.CommandExecuted += CheckUpdateRowCount; + if (deleteOptions.HasFlag(DeleteOptions.CheckRowsAffected)) + executionToken.CommandExecuted += CheckDeleteRowCount; return executionToken; } /// - /// Checks the delete row count. + /// Checks the update row count. /// /// /// The execution token. - /// The delete options. + /// The update options. /// The expected row count. /// The execution token with an attached event handler. - public static T CheckDeleteRowCount(this T executionToken, DeleteOptions deleteOptions, int? expectedRowCount) where T : ExecutionToken + public static T CheckUpdateRowCount(this T executionToken, UpdateOptions updateOptions, int? expectedRowCount) where T : ExecutionToken { if (executionToken == null) throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (expectedRowCount.HasValue && deleteOptions.HasFlag(DeleteOptions.CheckRowsAffected)) - executionToken.CommandExecuted += (s, e) => CheckDeleteRowCount(s, e, expectedRowCount.Value); + if (expectedRowCount.HasValue && !updateOptions.HasFlag(UpdateOptions.IgnoreRowsAffected)) + executionToken.CommandExecuted += (s, e) => CheckUpdateRowCount(s, e, expectedRowCount.Value); return executionToken; } /// - /// Checks the delete row count. + /// Checks the update row count. /// /// /// The execution token. - /// The delete options. + /// The update options. /// The execution token with an attached event handler. - public static T CheckDeleteRowCount(this T executionToken, DeleteOptions deleteOptions) where T : ExecutionToken + public static T CheckUpdateRowCount(this T executionToken, UpdateOptions updateOptions) where T : ExecutionToken { if (executionToken == null) throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (deleteOptions.HasFlag(DeleteOptions.CheckRowsAffected)) - executionToken.CommandExecuted += CheckDeleteRowCount; + if (!updateOptions.HasFlag(UpdateOptions.IgnoreRowsAffected)) + executionToken.CommandExecuted += CheckUpdateRowCount; return executionToken; } - internal static StreamingObjectConstructor AsObjectConstructor(this DbDataReader reader, ConstructorMetadata? constructor, IReadOnlyList nonNullableColumns) + internal static StreamingObjectConstructor AsObjectConstructor(this DbDataReader reader, ConstructorMetadata? constructor, IReadOnlyList nonNullableColumns, MaterializerTypeConverter converter) where T : class { - return new StreamingObjectConstructor(reader, constructor, nonNullableColumns); + return new StreamingObjectConstructor(reader, constructor, nonNullableColumns, converter); } - internal static StreamingObjectConstructor AsObjectConstructor(this DbDataReader reader, IReadOnlyList? constructorSignature, IReadOnlyList nonNullableColumns) + internal static StreamingObjectConstructor AsObjectConstructor(this DbDataReader reader, IReadOnlyList? constructorSignature, IReadOnlyList nonNullableColumns, MaterializerTypeConverter converter) where T : class { - return new StreamingObjectConstructor(reader, constructorSignature, nonNullableColumns); + return new StreamingObjectConstructor(reader, constructorSignature, nonNullableColumns, converter); } - static internal T ConstructObject(IReadOnlyDictionary source, ConstructorMetadata? constructor, bool? populateComplexObject = null) + static internal T ConstructObject(IReadOnlyDictionary source, ConstructorMetadata? constructor, MaterializerTypeConverter converter, bool? populateComplexObject = null) where T : class { //If we didn't get a constructor, look for a default constructor to use. @@ -130,7 +127,7 @@ static internal T ConstructObject(IReadOnlyDictionary source var result = (T)constructor.ConstructorInfo.Invoke(parameters); if (populateComplexObject.Value) //Populate properties and child objects - PopulateComplexObject(source, result, null); + PopulateComplexObject(source, result, null, converter); //Change tracking objects should be materialized as unchanged. (result as IChangeTracking)?.AcceptChanges(); @@ -141,12 +138,16 @@ static internal T ConstructObject(IReadOnlyDictionary source /// /// Populates the complex object. /// + /// /// The source. /// The object being populated. /// The decomposition prefix. + /// The type converter. + /// source + /// target /// This honors the Column and Decompose attributes. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - static internal void PopulateComplexObject(IReadOnlyDictionary source, T target, string? decompositionPrefix) + static internal void PopulateComplexObject(IReadOnlyDictionary source, T target, string? decompositionPrefix, MaterializerTypeConverter converter) where T : class { if (source == null) @@ -161,16 +162,16 @@ static internal void PopulateComplexObject(IReadOnlyDictionary(IReadOnlyDictionary source, T target, string? decompositionPrefix, IList> mappedProperties, IList> decomposedProperties) + static internal void PopulateComplexObject(IReadOnlyDictionary source, T target, string? decompositionPrefix, IList> mappedProperties, IList> decomposedProperties, MaterializerTypeConverter converter) where T : class { if (source == null) @@ -182,12 +183,12 @@ static internal void PopulateComplexObject(IReadOnlyDictionary { var value = source[property.Ordinal]; - SetProperty(target, property.PropertyMetadata, value, property); + SetProperty(target, property.PropertyMetadata, value, property, converter); } foreach (var property in decomposedProperties) { - SetDecomposedProperty((IReadOnlyDictionary)source, target, decompositionPrefix, property.PropertyMetadata); + SetDecomposedProperty((IReadOnlyDictionary)source, target, decompositionPrefix, property.PropertyMetadata, converter); } } @@ -242,9 +243,9 @@ static internal async Task RemainingRowCountAsync(this DbDataReader source) return result; } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UpdateOptions")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DeleteOptions")] [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IgnoreRowsAffected")] - static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e) + static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e) { if (sender == null) throw new ArgumentNullException(nameof(sender), $"{nameof(sender)} is null."); @@ -252,7 +253,7 @@ static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e) var token = (ExecutionToken)sender; if (e.RowsAffected == null) - throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either use the UpdateOptions.IgnoreRowsAffected flag or report this as an bug in {token.GetType().FullName}."); + throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either remove the DeleteOptions.CheckRowsAffected flag or report this as an bug in {token.GetType().FullName}."); else if (e.RowsAffected == 0) throw new MissingDataException($"Expected one row to be affected by the operation {token.OperationName} but none were."); else if (e.RowsAffected > 1) @@ -260,8 +261,8 @@ static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e) } [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IgnoreRowsAffected")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UpdateOptions")] - static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e, int expectedRowCount) + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DeleteOptions")] + static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e, int expectedRowCount) { if (sender == null) throw new ArgumentNullException(nameof(sender), $"{nameof(sender)} is null."); @@ -269,16 +270,16 @@ static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e, int var token = (ExecutionToken)sender; if (e.RowsAffected == null) - throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either use the UpdateOptions.IgnoreRowsAffected flag or report this as an bug in {token.GetType().FullName}."); + throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either remove the DeleteOptions.CheckRowsAffected flag or report this as an bug in {token.GetType().FullName}."); else if (e.RowsAffected > expectedRowCount) throw new UnexpectedDataException($"Expected {expectedRowCount} rows to be affected by the operation {token.OperationName} but {e.RowsAffected} were affected instead."); else if (e.RowsAffected < expectedRowCount) throw new MissingDataException($"Expected {expectedRowCount} rows to be affected by the operation {token.OperationName} but {e.RowsAffected} were affected instead."); } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DeleteOptions")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UpdateOptions")] [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IgnoreRowsAffected")] - static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e) + static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e) { if (sender == null) throw new ArgumentNullException(nameof(sender), $"{nameof(sender)} is null."); @@ -286,7 +287,7 @@ static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e) var token = (ExecutionToken)sender; if (e.RowsAffected == null) - throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either remove the DeleteOptions.CheckRowsAffected flag or report this as an bug in {token.GetType().FullName}."); + throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either use the UpdateOptions.IgnoreRowsAffected flag or report this as an bug in {token.GetType().FullName}."); else if (e.RowsAffected == 0) throw new MissingDataException($"Expected one row to be affected by the operation {token.OperationName} but none were."); else if (e.RowsAffected > 1) @@ -294,8 +295,8 @@ static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e) } [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IgnoreRowsAffected")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "DeleteOptions")] - static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e, int expectedRowCount) + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UpdateOptions")] + static void CheckUpdateRowCount(object? sender, CommandExecutedEventArgs e, int expectedRowCount) { if (sender == null) throw new ArgumentNullException(nameof(sender), $"{nameof(sender)} is null."); @@ -303,14 +304,14 @@ static void CheckDeleteRowCount(object? sender, CommandExecutedEventArgs e, int var token = (ExecutionToken)sender; if (e.RowsAffected == null) - throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either remove the DeleteOptions.CheckRowsAffected flag or report this as an bug in {token.GetType().FullName}."); + throw new InvalidOperationException($"The database did not report how many rows were affected by operation {token.OperationName}. Either use the UpdateOptions.IgnoreRowsAffected flag or report this as an bug in {token.GetType().FullName}."); else if (e.RowsAffected > expectedRowCount) throw new UnexpectedDataException($"Expected {expectedRowCount} rows to be affected by the operation {token.OperationName} but {e.RowsAffected} were affected instead."); else if (e.RowsAffected < expectedRowCount) throw new MissingDataException($"Expected {expectedRowCount} rows to be affected by the operation {token.OperationName} but {e.RowsAffected} were affected instead."); } - static void SetDecomposedProperty(IReadOnlyDictionary source, object target, string? decompositionPrefix, PropertyMetadata property) + static void SetDecomposedProperty(IReadOnlyDictionary source, object target, string? decompositionPrefix, PropertyMetadata property, MaterializerTypeConverter converter) { object? child = null; @@ -324,10 +325,10 @@ static void SetDecomposedProperty(IReadOnlyDictionary source, o } if (child != null) - PopulateComplexObject(source, child, decompositionPrefix + property.DecompositionPrefix); + PopulateComplexObject(source, child, decompositionPrefix + property.DecompositionPrefix, converter); } - static object? SetProperty(T target, PropertyMetadata property, object? value, OrdinalMappedProperty? mapper) + static object? SetProperty(T target, PropertyMetadata property, object? value, OrdinalMappedProperty? mapper, MaterializerTypeConverter converter) where T : class { if (target == null) @@ -340,62 +341,9 @@ static void SetDecomposedProperty(IReadOnlyDictionary source, o if (value != null && targetType != value.GetType()) { - var targetTypeInfo = targetType.GetTypeInfo(); - //var isNullable = !targetTypeInfo.IsValueType; - - //For Nullable, we only care about the type parameter - if (targetType.Name == "Nullable`1" && targetTypeInfo.IsGenericType) - { - //isNullable = true; - targetType = targetType.GenericTypeArguments[0]; - targetTypeInfo = targetType.GetTypeInfo(); - } - - //some database return strings when we want strong types - if (value is string) - { - if (targetType == typeof(XElement)) - value = XElement.Parse((string)value); - else if (targetType == typeof(XDocument)) - value = XDocument.Parse((string)value); - else if (targetTypeInfo.IsEnum) - value = Enum.Parse(targetType, (string)value); - else if (targetType == typeof(bool)) - value = bool.Parse((string)value); - else if (targetType == typeof(short)) - value = short.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(int)) - value = int.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(long)) - value = long.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(float)) - value = float.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(double)) - value = double.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(decimal)) - value = decimal.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(DateTime)) - value = DateTime.Parse((string)value, CultureInfo.InvariantCulture); - else if (targetType == typeof(DateTimeOffset)) - value = DateTimeOffset.Parse((string)value, CultureInfo.InvariantCulture); - } - else - { - if (targetTypeInfo.IsEnum) - value = Enum.ToObject(targetType, value); - } - - //this will handle numeric conversions - if (value != null && targetType != value.GetType()) + if (!converter.TryConvertType(targetType, ref value, out var conversionException)) { - try - { - value = Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture); - } - catch (Exception ex) - { - throw new MappingException($"Cannot map value of type {value.GetType().FullName} to property {property.Name} of type {targetType.Name}.", ex); - } + throw new MappingException($"Cannot map value of type {value!.GetType().FullName} to property {property.Name} of type {targetType.Name}.", conversionException); } } @@ -407,4 +355,4 @@ static void SetDecomposedProperty(IReadOnlyDictionary source, o return value; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`2.cs index 05d3ba806..dabde2cc7 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`2.cs @@ -2,59 +2,57 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This is the base class for materializers that don't return a value. Most operation are not executed without first attaching a materializer subclass. +/// +/// The type of the t command type. +/// The type of the t parameter type. +public abstract class Materializer : Materializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// This is the base class for materializers that don't return a value. Most operation are not executed without first attaching a materializer subclass. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - public abstract class Materializer : Materializer - where TCommand : DbCommand - where TParameter : DbParameter + /// The associated command builder. + /// operation;operation is null. + protected Materializer(DbCommandBuilder commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The associated command builder. - /// operation;operation is null. - protected Materializer(DbCommandBuilder commandBuilder) - { - CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); - } - - /// - /// Gets the associated operation. - /// - /// The command builder. - protected DbCommandBuilder CommandBuilder { get; } - - - /// - /// Gets the command behavior to be used by materializers. - /// - /// This value is calculated from the CommandBuilder. - protected CommandBehavior CommandBehavior => CommandBuilder.SequentialAccessMode ? CommandBehavior.SequentialAccess : CommandBehavior.Default; - - /// - /// Returns the command text (usually SQL) without executing it. - /// - /// System.String. - public string? CommandText() => CommandBuilder.Prepare(this).CommandText; - - /// - /// Prepares this operation for execution. - /// - /// ExecutionToken<TCommand, TParameter>. - protected CommandExecutionToken Prepare() - { - OnExecutionTokenPreparing(new ExecutionTokenPreparingEventArgs(CommandBuilder)); - - var executionToken = CommandBuilder.Prepare(this); - - OnExecutionTokenPrepared(new ExecutionTokenPreparedEventArgs(executionToken)); - - return executionToken; - } + CommandBuilder = commandBuilder ?? throw new ArgumentNullException(nameof(commandBuilder), $"{nameof(commandBuilder)} is null."); + } + + /// + /// Gets the command behavior to be used by materializers. + /// + /// This value is calculated from the CommandBuilder. + protected CommandBehavior CommandBehavior => CommandBuilder.SequentialAccessMode ? CommandBehavior.SequentialAccess : CommandBehavior.Default; + + /// + /// Gets the associated operation. + /// + /// The command builder. + protected DbCommandBuilder CommandBuilder { get; } + + /// + /// Returns the command text (usually SQL) without executing it. + /// + /// System.String. + public string? CommandText() => CommandBuilder.Prepare(this).CommandText; + + /// + /// Prepares this operation for execution. + /// + /// ExecutionToken<TCommand, TParameter>. + protected CommandExecutionToken Prepare() + { + OnExecutionTokenPreparing(new ExecutionTokenPreparingEventArgs(CommandBuilder)); + + var executionToken = CommandBuilder.Prepare(this); + + OnExecutionTokenPrepared(new ExecutionTokenPreparedEventArgs(executionToken)); + + return executionToken; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`3.cs index 519bb671e..518b3931f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Materializer`3.cs @@ -1,55 +1,60 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.DataSources; +using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This is the base class for materializers that return a value. Most operation are not executed without first attaching a materializer subclass. +/// Implements the +/// Implements the +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the result. +/// +/// +/// +public abstract class Materializer : Materializer, ILink + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// This is the base class for materializers that return a value. Most operation are not executed without first attaching a materializer subclass. - /// Implements the - /// Implements the + /// Initializes a new instance of the class. + /// + /// The associated operation. + protected Materializer(DbCommandBuilder commandBuilder) : base(commandBuilder) { } + + /// + /// Gets the data source that is associated with this materializer or appender. /// - /// The type of the command. - /// The type of the parameter. - /// The type of the result. - /// - /// - /// - public abstract class Materializer : Materializer, ILink - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - protected Materializer(DbCommandBuilder commandBuilder) : base(commandBuilder) { } + /// The data source. + public IDataSource DataSource => CommandBuilder.DataSource; - /// - /// Gets the data source that is associated with this materializer or appender. - /// - /// The data source. - public IDataSource DataSource => CommandBuilder.DataSource; + /// + /// Gets the type converter associated with this materializer. + /// + protected MaterializerTypeConverter Converter => CommandBuilder.DataSource.DatabaseMetadata.Converter; - /// - /// Execute the operation synchronously. - /// - /// - public abstract TResult Execute(object? state = null); + /// + /// Execute the operation synchronously. + /// + /// + public abstract TResult Execute(object? state = null); - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// - public async Task ExecuteAsync(object? state = null) => await ExecuteAsync(CancellationToken.None, state).ConfigureAwait(false); + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// + public async Task ExecuteAsync(object? state = null) => await ExecuteAsync(CancellationToken.None, state).ConfigureAwait(false); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public abstract Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); - } + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public abstract Task ExecuteAsync(CancellationToken cancellationToken, object? state = null); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleBatcher.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleBatcher.cs deleted file mode 100644 index 18a56923c..000000000 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleBatcher.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Tortuga.Chain.CommandBuilders -{ - ///// - ///// MultiBatcher is used by InsertMultipleBatch to perform a series of batch inserts. - ///// - //internal class MultiBatcher : ILink - //{ - // int m_BatchSize; - - // Func, ILink> m_CallBack; - - // IEnumerable m_Objects; - - // internal MultiBatcher(IDataSource dataSource, Func, ILink> callBack, IEnumerable objects, int batchSize) - // { - // DataSource = dataSource; - // m_CallBack = callBack; - // m_Objects = objects; - // m_BatchSize = batchSize; - // } - - // public event EventHandler? ExecutionTokenPrepared; - - // public event EventHandler? ExecutionTokenPreparing; - - // public IDataSource DataSource { get; } - - // string? ILink.CommandText() - // { - // var result = new System.Text.StringBuilder(); - // foreach (var batch in m_Objects.BatchAsLists(m_BatchSize)) - // { - // ILink link = m_CallBack.Invoke(batch); - // link.ExecutionTokenPrepared += OnExecutionTokenPrepared; - // link.ExecutionTokenPreparing += OnExecutionTokenPreparing; - // result.AppendLine(link.CommandText()); - // link.ExecutionTokenPrepared -= OnExecutionTokenPrepared; - // link.ExecutionTokenPreparing -= OnExecutionTokenPreparing; - // } - - // return result.ToString(); - // } - - // int ILink.Execute(object? state) - // { - // var result = 0; - // foreach (var batch in m_Objects.BatchAsLists(m_BatchSize)) - // { - // ILink link = m_CallBack.Invoke(batch); - // link.ExecutionTokenPrepared += OnExecutionTokenPrepared; - // link.ExecutionTokenPreparing += OnExecutionTokenPreparing; - // result += link.Execute(state); - // link.ExecutionTokenPrepared -= OnExecutionTokenPrepared; - // link.ExecutionTokenPreparing -= OnExecutionTokenPreparing; - // } - - // return result; - // } - - // Task ILink.ExecuteAsync(object? state) - // { - // return ((ILink)this).ExecuteAsync(CancellationToken.None, state); - // } - - // async Task ILink.ExecuteAsync(CancellationToken cancellationToken, object? state) - // { - // var result = 0; - // foreach (var batch in m_Objects.BatchAsLists(m_BatchSize)) - // { - // ILink link = m_CallBack.Invoke(batch); - // link.ExecutionTokenPrepared += OnExecutionTokenPrepared; - // link.ExecutionTokenPreparing += OnExecutionTokenPreparing; - // result += await link.ExecuteAsync(cancellationToken, state).ConfigureAwait(false); - // link.ExecutionTokenPrepared -= OnExecutionTokenPrepared; - // link.ExecutionTokenPreparing -= OnExecutionTokenPreparing; - // } - - // return result; - // } - - - - // void OnExecutionTokenPrepared(object? sender, ExecutionTokenPreparedEventArgs e) - // { - // ExecutionTokenPrepared?.Invoke(sender, e); - // } - - // void OnExecutionTokenPreparing(object? sender, ExecutionTokenPreparingEventArgs e) - // { - // ExecutionTokenPreparing?.Invoke(sender, e); - // } - //} -} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/CollectionMaterializer`4.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/CollectionMaterializer`4.cs index 2b13beea0..68f8f4987 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/CollectionMaterializer`4.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/CollectionMaterializer`4.cs @@ -2,81 +2,80 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a collection of the indicated type. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the object returned. +/// The type of the collection. +/// +[SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] +internal sealed class CollectionMaterializer : ConstructibleMaterializer + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class + where TCollection : ICollection, new() { + readonly CollectionOptions m_CollectionOptions; + /// - /// Materializes the result set as a collection of the indicated type. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the object returned. - /// The type of the collection. - /// - [SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] - internal sealed class CollectionMaterializer : ConstructibleMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class - where TCollection : ICollection, new() + /// The associated operation. + /// The collection options. + public CollectionMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) + : base(commandBuilder) { - readonly CollectionOptions m_CollectionOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - /// The collection options. - public CollectionMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) - : base(commandBuilder) - { - m_CollectionOptions = collectionOptions; + m_CollectionOptions = collectionOptions; - if (m_CollectionOptions.HasFlag(CollectionOptions.InferConstructor)) - Constructor = InferConstructor(); - } + if (m_CollectionOptions.HasFlag(CollectionOptions.InferConstructor)) + Constructor = InferConstructor(); + } - /// - /// Execute the operation synchronously. - /// - /// - public override TCollection Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// + public override TCollection Execute(object? state = null) + { + var result = new TCollection(); + Prepare().Execute(cmd => { - var result = new TCollection(); - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - while (reader.Read(out var value)) - result.Add(value); - return result.Count; - } - }, state); + while (reader.Read(out var value)) + result.Add(value); + return result.Count; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new TCollection(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new TCollection(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - while (await reader.ReadAsync().ConfigureAwait(false)) - result.Add(reader.Current!); - return result.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + while (await reader.ReadAsync().ConfigureAwait(false)) + result.Add(reader.Current!); + return result.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DataTableMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DataTableMaterializer`2.cs index 789494141..a3ed8d449 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DataTableMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DataTableMaterializer`2.cs @@ -2,80 +2,79 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a DataTable. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DataTableMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a DataTable. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DataTableMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - public DataTableMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { } + /// The associated operation. + public DataTableMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) + { } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - public override DataTable Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + public override DataTable Execute(object? state = null) + { + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + var dt = new DataTable(); + ds.Tables.Add(dt); + Prepare().Execute(cmd => { - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - var dt = new DataTable(); - ds.Tables.Add(dt); - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - dt.Load(reader); - return dt.Rows.Count; - } - }, state); + dt.Load(reader); + return dt.Rows.Count; + } + }, state); - return dt; - } + return dt; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "")] - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "")] + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + var dt = new DataTable(); + ds.Tables.Add(dt); + await Prepare().ExecuteAsync(async cmd => { - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - var dt = new DataTable(); - ds.Tables.Add(dt); - await Prepare().ExecuteAsync(async cmd => + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - dt.Load(reader); - return dt.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + dt.Load(reader); + return dt.Rows.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - return dt; - } + return dt; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DictionaryMaterializer`5.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DictionaryMaterializer`5.cs index ab5db48ba..9d6fa6d76 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DictionaryMaterializer`5.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DictionaryMaterializer`5.cs @@ -1,104 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers -{ - /// - /// Materializes the result set as a dictionary of the indicated type. - /// - /// The type of the command. - /// The type of the parameter. - /// The type of the key. - /// The type of the object. - /// The type of the dictionary. - /// - internal class DictionaryMaterializer : ConstructibleMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - where TKey : notnull - where TObject : class - where TDictionary : IDictionary, new() - { - readonly DictionaryOptions m_DictionaryOptions; - readonly string? m_KeyColumn; - readonly Func? m_KeyFunction; +namespace Tortuga.Chain.Materializers; - public DictionaryMaterializer(DbCommandBuilder commandBuilder, Func keyFunction, DictionaryOptions dictionaryOptions) : base(commandBuilder) - { - m_KeyFunction = keyFunction; - m_DictionaryOptions = dictionaryOptions; +/// +/// Materializes the result set as a dictionary of the indicated type. +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the key. +/// The type of the object. +/// The type of the dictionary. +/// +internal class DictionaryMaterializer : ConstructibleMaterializer + where TCommand : DbCommand + where TParameter : DbParameter + where TKey : notnull + where TObject : class + where TDictionary : IDictionary, new() +{ + readonly DictionaryOptions m_DictionaryOptions; + readonly string? m_KeyColumn; + readonly Func? m_KeyFunction; - if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) - Constructor = InferConstructor(); - } + public DictionaryMaterializer(DbCommandBuilder commandBuilder, Func keyFunction, DictionaryOptions dictionaryOptions) : base(commandBuilder) + { + m_KeyFunction = keyFunction; + m_DictionaryOptions = dictionaryOptions; - public DictionaryMaterializer(DbCommandBuilder commandBuilder, string keyColumn, DictionaryOptions dictionaryOptions) : base(commandBuilder) - { - m_KeyColumn = commandBuilder.TryGetColumn(keyColumn)?.SqlName ?? keyColumn; - m_DictionaryOptions = dictionaryOptions; + if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) + Constructor = InferConstructor(); + } - if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) - Constructor = InferConstructor(); + public DictionaryMaterializer(DbCommandBuilder commandBuilder, string keyColumn, DictionaryOptions dictionaryOptions) : base(commandBuilder) + { + m_KeyColumn = commandBuilder.TryGetColumn(keyColumn)?.SqlName ?? keyColumn; + m_DictionaryOptions = dictionaryOptions; - } + if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) + Constructor = InferConstructor(); + } - public override TDictionary Execute(object? state = null) + public override TDictionary Execute(object? state = null) + { + var result = new TDictionary(); + Prepare().Execute(cmd => { - var result = new TDictionary(); - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - while (reader.Read(out var value)) - AddToDictionary(result, reader, value); + while (reader.Read(out var value)) + AddToDictionary(result, reader, value); - return reader.RowsRead; - } - }, state); + return reader.RowsRead; + } + }, state); - return result; - } + return result; + } - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new TDictionary(); + await Prepare().ExecuteAsync(async cmd => { - var result = new TDictionary(); - await Prepare().ExecuteAsync(async cmd => + using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - while (await reader.ReadAsync().ConfigureAwait(false)) - AddToDictionary(result, reader, reader.Current!); + while (await reader.ReadAsync().ConfigureAwait(false)) + AddToDictionary(result, reader, reader.Current!); - return reader.RowsRead; - } - }, cancellationToken, state).ConfigureAwait(false); + return reader.RowsRead; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; + } - void AddToDictionary(TDictionary result, StreamingObjectConstructor source, TObject value) + void AddToDictionary(TDictionary result, StreamingObjectConstructor source, TObject value) + { + if (m_KeyFunction != null) { - if (m_KeyFunction != null) - { - if (m_DictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) - result[m_KeyFunction(value)] = value; - else - result.Add(m_KeyFunction(value), value); - } - else if (m_KeyColumn != null) - { - if (!source.CurrentDictionary.ContainsKey(m_KeyColumn)) - throw new MappingException("The result set does not contain a column named " + m_KeyColumn); + if (m_DictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) + result[m_KeyFunction(value)] = value; + else + result.Add(m_KeyFunction(value), value); + } + else if (m_KeyColumn != null) + { + if (!source.CurrentDictionary.ContainsKey(m_KeyColumn)) + throw new MappingException("The result set does not contain a column named " + m_KeyColumn); - var key = source.CurrentDictionary[m_KeyColumn]; - if (key == null) - throw new MissingDataException("Key column is null"); + var key = source.CurrentDictionary[m_KeyColumn]; + if (key == null) + throw new MissingDataException("Key column is null"); - if (m_DictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) - result[(TKey)key] = value; - else - result.Add((TKey)key, value); - } + if (m_DictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) + result[(TKey)key] = value; + else + result.Add((TKey)key, value); } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DynamicCollectionMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DynamicCollectionMaterializer`2.cs index a9b462404..c3951eb27 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DynamicCollectionMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/DynamicCollectionMaterializer`2.cs @@ -2,96 +2,95 @@ using System.Dynamic; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a List of dynamic objects. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DynamicCollectionMaterializer : Materializer> where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a List of dynamic objects. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DynamicCollectionMaterializer : Materializer> where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - public DynamicCollectionMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { } + /// The associated operation. + public DynamicCollectionMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) + { } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); + Prepare().Execute(cmd => { - var result = new List(); - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + while (reader.Read()) { - while (reader.Read()) + IDictionary item = new ExpandoObject(); + for (var i = 0; i < reader.FieldCount; i++) { - IDictionary item = new ExpandoObject(); - for (var i = 0; i < reader.FieldCount; i++) - { - if (reader.IsDBNull(i)) - item[reader.GetName(i)] = null; - else - item[reader.GetName(i)] = reader.GetValue(i); - } - result.Add(item); + if (reader.IsDBNull(i)) + item[reader.GetName(i)] = null; + else + item[reader.GetName(i)] = reader.GetValue(i); } - return result.Count; + result.Add(item); } - }, state); + return result.Count; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + IDictionary item = new ExpandoObject(); + for (var i = 0; i < reader.FieldCount; i++) { - IDictionary item = new ExpandoObject(); - for (var i = 0; i < reader.FieldCount; i++) - { - if (reader.IsDBNull(i)) - item[reader.GetName(i)] = null; - else - item[reader.GetName(i)] = reader.GetValue(i); - } - result.Add(item); + if (reader.IsDBNull(i)) + item[reader.GetName(i)] = null; + else + item[reader.GetName(i)] = reader.GetValue(i); } - return result.Count; + result.Add(item); } - }, cancellationToken, state).ConfigureAwait(false); + return result.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableArrayMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableArrayMaterializer`3.cs index 1f41ec001..fa5264922 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableArrayMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableArrayMaterializer`3.cs @@ -3,77 +3,75 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an immutable array of the indicated type. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the object returned. +/// +[SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] +internal sealed class ImmutableArrayMaterializer : ConstructibleMaterializer, TObject> + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class { + readonly CollectionOptions m_CollectionOptions; + /// - /// Materializes the result set as an immutable array of the indicated type. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the object returned. - /// - [SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] - internal sealed class ImmutableArrayMaterializer : ConstructibleMaterializer, TObject> - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class + /// The associated operation. + /// The collection options. + public ImmutableArrayMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) + : base(commandBuilder) { - readonly CollectionOptions m_CollectionOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - /// The collection options. - public ImmutableArrayMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) - : base(commandBuilder) - { - m_CollectionOptions = collectionOptions; + m_CollectionOptions = collectionOptions; - if (m_CollectionOptions.HasFlag(CollectionOptions.InferConstructor)) - Constructor = InferConstructor(); - - } + if (m_CollectionOptions.HasFlag(CollectionOptions.InferConstructor)) + Constructor = InferConstructor(); + } - /// - /// Execute the operation synchronously. - /// - /// - public override ImmutableArray Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// + public override ImmutableArray Execute(object? state = null) + { + ImmutableArray result = default; + Prepare().Execute(cmd => { - ImmutableArray result = default; - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - result = reader.ToObjects().ToImmutableArray(); - return result.Length; - } - }, state); + result = reader.ToObjects().ToImmutableArray(); + return result.Length; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + ImmutableArray result = default; + await Prepare().ExecuteAsync(async cmd => { - ImmutableArray result = default; - await Prepare().ExecuteAsync(async cmd => + using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - result = (await reader.ToListAsync().ConfigureAwait(false)).ToImmutableArray(); - return result.Length; - } - }, cancellationToken, state).ConfigureAwait(false); + result = (await reader.ToListAsync().ConfigureAwait(false)).ToImmutableArray(); + return result.Length; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableDictionaryMaterializer`4.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableDictionaryMaterializer`4.cs index 9dffb916b..dc2f11dbd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableDictionaryMaterializer`4.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableDictionaryMaterializer`4.cs @@ -2,101 +2,96 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a dictionary of the indicated type. +/// +/// The type of the command. +/// The type of the parameter. +/// The type of the key. +/// The type of the object. +/// +internal class ImmutableDictionaryMaterializer : ConstructibleMaterializer, TObject> + where TCommand : DbCommand + where TParameter : DbParameter + where TKey : notnull + where TObject : class { - /// - /// Materializes the result set as a dictionary of the indicated type. - /// - /// The type of the command. - /// The type of the parameter. - /// The type of the key. - /// The type of the object. - /// - internal class ImmutableDictionaryMaterializer : ConstructibleMaterializer, TObject> - where TCommand : DbCommand - where TParameter : DbParameter - where TKey : notnull - where TObject : class - { - readonly DictionaryOptions m_DictionaryOptions; - readonly string? m_KeyColumn; - readonly Func? m_KeyFunction; - - public ImmutableDictionaryMaterializer(DbCommandBuilder commandBuilder, Func keyFunction, DictionaryOptions dictionaryOptions) : base(commandBuilder) - { - if (dictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) - throw new NotImplementedException("DiscardDuplicates is not implemented for ImmutableDictionary with default constructors."); - - m_KeyFunction = keyFunction; - m_DictionaryOptions = dictionaryOptions; - - if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) - Constructor = InferConstructor(); - - } + readonly DictionaryOptions m_DictionaryOptions; + readonly string? m_KeyColumn; + readonly Func? m_KeyFunction; - public ImmutableDictionaryMaterializer(DbCommandBuilder commandBuilder, string keyColumn, DictionaryOptions dictionaryOptions) : base(commandBuilder) - { - if (dictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) - throw new NotImplementedException("DiscardDuplicates is not implemented for ImmutableDictionary with default constructors."); + public ImmutableDictionaryMaterializer(DbCommandBuilder commandBuilder, Func keyFunction, DictionaryOptions dictionaryOptions) : base(commandBuilder) + { + if (dictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) + throw new NotImplementedException("DiscardDuplicates is not implemented for ImmutableDictionary with default constructors."); - m_KeyColumn = commandBuilder.TryGetColumn(keyColumn)?.SqlName ?? keyColumn; - m_DictionaryOptions = dictionaryOptions; + m_KeyFunction = keyFunction; + m_DictionaryOptions = dictionaryOptions; - if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) - Constructor = InferConstructor(); + if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) + Constructor = InferConstructor(); + } - } + public ImmutableDictionaryMaterializer(DbCommandBuilder commandBuilder, string keyColumn, DictionaryOptions dictionaryOptions) : base(commandBuilder) + { + if (dictionaryOptions.HasFlag(DictionaryOptions.DiscardDuplicates)) + throw new NotImplementedException("DiscardDuplicates is not implemented for ImmutableDictionary with default constructors."); + m_KeyColumn = commandBuilder.TryGetColumn(keyColumn)?.SqlName ?? keyColumn; + m_DictionaryOptions = dictionaryOptions; + if (m_DictionaryOptions.HasFlag(DictionaryOptions.InferConstructor)) + Constructor = InferConstructor(); + } - public override ImmutableDictionary Execute(object? state = null) + public override ImmutableDictionary Execute(object? state = null) + { + Table? table = null; + Prepare().Execute(cmd => { - Table? table = null; - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, state); - - return ToDictionary(table!); - } + table = new Table(reader, Converter); + return table.Rows.Count; + } + }, state); + + return ToDictionary(table!); + } - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + Table? table = null; + await Prepare().ExecuteAsync(async cmd => { - Table? table = null; - await Prepare().ExecuteAsync(async cmd => + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); - - return ToDictionary(table!); - } + table = new Table(reader, Converter); + return table.Rows.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - ImmutableDictionary ToDictionary(Table table) - { - if (m_KeyFunction != null) - return ImmutableDictionary.CreateRange(table.ToObjects(Constructor).Select(x => new KeyValuePair(m_KeyFunction(x), x))); + return ToDictionary(table!); + } - if (!table.ColumnNames.Contains(m_KeyColumn)) - throw new MappingException("The result set does not contain a column named " + m_KeyColumn); + ImmutableDictionary ToDictionary(Table table) + { + if (m_KeyFunction != null) + return ImmutableDictionary.CreateRange(table.ToObjects(Constructor).Select(x => new KeyValuePair(m_KeyFunction(x), x))); - return ImmutableDictionary.CreateRange(table.ToObjectsWithEcho(Constructor).Select(x => NewMethod(x))); + if (!table.ColumnNames.Contains(m_KeyColumn)) + throw new MappingException("The result set does not contain a column named " + m_KeyColumn); - KeyValuePair NewMethod(KeyValuePair x) - { - var key = x.Key[m_KeyColumn!]; - if (key == null) - throw new UnexpectedDataException("Key is null"); - return new KeyValuePair((TKey)key, x.Value); - } + return ImmutableDictionary.CreateRange(table.ToObjectsWithEcho(Constructor).Select(x => NewMethod(x))); + + KeyValuePair NewMethod(KeyValuePair x) + { + var key = x.Key[m_KeyColumn!]; + if (key == null) + throw new UnexpectedDataException("Key is null"); + return new KeyValuePair((TKey)key, x.Value); } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableListMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableListMaterializer`3.cs index f134b5a27..e3be352e5 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableListMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/ImmutableListMaterializer`3.cs @@ -3,78 +3,76 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an immutable list of the indicated type. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the object returned. +/// +[SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] +internal sealed class ImmutableListMaterializer : ConstructibleMaterializer, TObject> + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class { + readonly CollectionOptions m_CollectionOptions; + /// - /// Materializes the result set as an immutable list of the indicated type. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the object returned. - /// - [SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")] - internal sealed class ImmutableListMaterializer : ConstructibleMaterializer, TObject> - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class + /// The associated operation. + /// The collection options. + public ImmutableListMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) + : base(commandBuilder) { - readonly CollectionOptions m_CollectionOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - /// The collection options. - public ImmutableListMaterializer(DbCommandBuilder commandBuilder, CollectionOptions collectionOptions) - : base(commandBuilder) - { - m_CollectionOptions = collectionOptions; + m_CollectionOptions = collectionOptions; - if (m_CollectionOptions.HasFlag(CollectionOptions.InferConstructor)) - Constructor = InferConstructor(); - - } + if (m_CollectionOptions.HasFlag(CollectionOptions.InferConstructor)) + Constructor = InferConstructor(); + } - /// - /// Execute the operation synchronously. - /// - /// The state. - /// ImmutableList<TObject>. - public override ImmutableList Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// The state. + /// ImmutableList<TObject>. + public override ImmutableList Execute(object? state = null) + { + ImmutableList? result = null; + Prepare().Execute(cmd => { - ImmutableList? result = null; - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = cmd.ExecuteReader().AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - result = reader.ToObjects().ToImmutableList(); - return result.Count; - } - }, state); + result = reader.ToObjects().ToImmutableList(); + return result.Count; + } + }, state); - return result!; - } + return result!; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + ImmutableList? result = null; + await Prepare().ExecuteAsync(async cmd => { - ImmutableList? result = null; - await Prepare().ExecuteAsync(async cmd => + using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns(), Converter)) { - using (var reader = (await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false)).AsObjectConstructor(Constructor, CommandBuilder.TryGetNonNullableColumns())) - { - result = (await reader.ToListAsync().ConfigureAwait(false)).ToImmutableList(); - return result.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + result = (await reader.ToListAsync().ConfigureAwait(false)).ToImmutableList(); + return result.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - return result!; - } + return result!; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/TableMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/TableMaterializer`2.cs index 8076f945f..c13671514 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/TableMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleRow/TableMaterializer`2.cs @@ -1,76 +1,75 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a Table. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TableMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a Table. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TableMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - public TableMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { } + /// The associated operation. + public TableMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) + { } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() - { - return AllColumns; - } + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() + { + return AllColumns; + } - /// - /// Execute the operation synchronously. - /// - /// - public override Table Execute(object? state) + /// + /// Execute the operation synchronously. + /// + /// + public override Table Execute(object? state) + { + Table? table = null; + Prepare().Execute(cmd => { - Table? table = null; - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, state); + table = new Table(reader, Converter); + return table.Rows.Count; + } + }, state); - return table!; - } + return table!; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task
ExecuteAsync(CancellationToken cancellationToken, object? state = null) + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task
ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + Table? table = null; + await Prepare().ExecuteAsync(async cmd => { - Table? table = null; - await Prepare().ExecuteAsync(async cmd => + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + table = new Table(reader, Converter); + return table.Rows.Count; + } + }, cancellationToken, state).ConfigureAwait(false); - return table!; - } + return table!; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`4.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`4.cs index ef0cdcd3b..84570e4c6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`4.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`4.cs @@ -1,95 +1,94 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TableSet. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the 1. +/// The type of the 2. +internal sealed class CollectionSetMaterializer : Materializer, List>> + where TCommand : DbCommand + where TParameter : DbParameter + where T1 : class, new() + where T2 : class, new() { /// - /// Materializes the result set as a TableSet. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the 1. - /// The type of the 2. - internal sealed class CollectionSetMaterializer : Materializer, List>> - where TCommand : DbCommand - where TParameter : DbParameter - where T1 : class, new() - where T2 : class, new() + /// The command builder. + public CollectionSetMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - public CollectionSetMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { - } + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// - public override Tuple, List> Execute(object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation synchronously. + /// + /// + public override Tuple, List> Execute(object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); - executionToken.Execute(cmd => + var executionToken = Prepare(); + executionToken.Execute(cmd => + { + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, state); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, state); - return BuildResult(result!); - } + return BuildResult(result!); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, cancellationToken, state).ConfigureAwait(false); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, cancellationToken, state).ConfigureAwait(false); - return BuildResult(result!); - } + return BuildResult(result!); + } - static Tuple, List> BuildResult(TableSet result) - { - if (result.Count != 2) - throw new DataException($"Expected 2 tables but received {result.Count} tables"); + static Tuple, List> BuildResult(TableSet result) + { + if (result.Count != 2) + throw new DataException($"Expected 2 tables but received {result.Count} tables"); - return Tuple.Create( - result[0].ToObjects().ToList(), - result[1].ToObjects().ToList() - ); - } + return Tuple.Create( + result[0].ToObjects().ToList(), + result[1].ToObjects().ToList() + ); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`5.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`5.cs index a21c9f881..8e407d297 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`5.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`5.cs @@ -1,98 +1,97 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TableSet. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the 1. +/// The type of the 2. +/// The type of the 3. +internal sealed class CollectionSetMaterializer : Materializer, List, List>> + where TCommand : DbCommand + where TParameter : DbParameter + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() { /// - /// Materializes the result set as a TableSet. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the 1. - /// The type of the 2. - /// The type of the 3. - internal sealed class CollectionSetMaterializer : Materializer, List, List>> - where TCommand : DbCommand - where TParameter : DbParameter - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() + /// The command builder. + public CollectionSetMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - public CollectionSetMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { - } + } + + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Execute the operation synchronously. + /// + /// + public override Tuple, List, List> Execute(object? state = null) + { + TableSet? result = null; - /// - /// Execute the operation synchronously. - /// - /// - public override Tuple, List, List> Execute(object? state = null) + var executionToken = Prepare(); + executionToken.Execute(cmd => { - TableSet? result = null; - - var executionToken = Prepare(); - executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, state); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, state); - return BuildResult(result!); - } + return BuildResult(result!); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task, List, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task, List, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, cancellationToken, state).ConfigureAwait(false); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, cancellationToken, state).ConfigureAwait(false); - return BuildResult(result!); - } + return BuildResult(result!); + } - static Tuple, List, List> BuildResult(TableSet result) - { - if (result.Count != 3) - throw new DataException($"Expected 3 tables but received {result.Count} tables"); + static Tuple, List, List> BuildResult(TableSet result) + { + if (result.Count != 3) + throw new DataException($"Expected 3 tables but received {result.Count} tables"); - return Tuple.Create( - result[0].ToObjects().ToList(), - result[1].ToObjects().ToList(), - result[2].ToObjects().ToList() - ); - } + return Tuple.Create( + result[0].ToObjects().ToList(), + result[1].ToObjects().ToList(), + result[2].ToObjects().ToList() + ); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`6.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`6.cs index 74dde1c57..0441ece8c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`6.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`6.cs @@ -1,101 +1,100 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TableSet. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the 1. +/// The type of the 2. +/// The type of the 3. +/// The type of the 4. +internal sealed class CollectionSetMaterializer : Materializer, List, List, List>> + where TCommand : DbCommand + where TParameter : DbParameter + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + where T4 : class, new() { /// - /// Materializes the result set as a TableSet. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the 1. - /// The type of the 2. - /// The type of the 3. - /// The type of the 4. - internal sealed class CollectionSetMaterializer : Materializer, List, List, List>> - where TCommand : DbCommand - where TParameter : DbParameter - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - where T4 : class, new() + /// The command builder. + public CollectionSetMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - public CollectionSetMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { - } + } + + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Execute the operation synchronously. + /// + /// + public override Tuple, List, List, List> Execute(object? state = null) + { + TableSet? result = null; - /// - /// Execute the operation synchronously. - /// - /// - public override Tuple, List, List, List> Execute(object? state = null) + var executionToken = Prepare(); + executionToken.Execute(cmd => { - TableSet? result = null; - - var executionToken = Prepare(); - executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, state); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, state); - return BuildResult(result!); - } + return BuildResult(result!); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task, List, List, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task, List, List, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, cancellationToken, state).ConfigureAwait(false); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, cancellationToken, state).ConfigureAwait(false); - return BuildResult(result!); - } + return BuildResult(result!); + } - static Tuple, List, List, List> BuildResult(TableSet result) - { - if (result.Count != 4) - throw new DataException($"Expected 4 tables but received {result.Count} tables"); + static Tuple, List, List, List> BuildResult(TableSet result) + { + if (result.Count != 4) + throw new DataException($"Expected 4 tables but received {result.Count} tables"); - return Tuple.Create( - result[0].ToObjects().ToList(), - result[1].ToObjects().ToList(), - result[2].ToObjects().ToList(), - result[3].ToObjects().ToList() - ); - } + return Tuple.Create( + result[0].ToObjects().ToList(), + result[1].ToObjects().ToList(), + result[2].ToObjects().ToList(), + result[3].ToObjects().ToList() + ); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`7.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`7.cs index 461f2a38e..02cc35217 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`7.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/CollectionSetMaterializer`7.cs @@ -1,104 +1,103 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TableSet. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the 1. +/// The type of the 2. +/// The type of the 3. +/// The type of the 4. +/// The type of the 5. +internal sealed class CollectionSetMaterializer : Materializer, List, List, List, List>> + where TCommand : DbCommand + where TParameter : DbParameter + where T1 : class, new() + where T2 : class, new() + where T3 : class, new() + where T4 : class, new() + where T5 : class, new() { /// - /// Materializes the result set as a TableSet. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the 1. - /// The type of the 2. - /// The type of the 3. - /// The type of the 4. - /// The type of the 5. - internal sealed class CollectionSetMaterializer : Materializer, List, List, List, List>> - where TCommand : DbCommand - where TParameter : DbParameter - where T1 : class, new() - where T2 : class, new() - where T3 : class, new() - where T4 : class, new() - where T5 : class, new() + /// The command builder. + public CollectionSetMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - public CollectionSetMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { - } + } + + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Execute the operation synchronously. + /// + /// + public override Tuple, List, List, List, List> Execute(object? state = null) + { + TableSet? result = null; - /// - /// Execute the operation synchronously. - /// - /// - public override Tuple, List, List, List, List> Execute(object? state = null) + var executionToken = Prepare(); + executionToken.Execute(cmd => { - TableSet? result = null; - - var executionToken = Prepare(); - executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, state); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, state); - return BuildResult(result!); - } + return BuildResult(result!); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task, List, List, List, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task, List, List, List, List>> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) - { - result = new TableSet(reader); - return result.Sum(t => t.Rows.Count); - } - }, cancellationToken, state).ConfigureAwait(false); + result = new TableSet(reader, Converter); + return result.Sum(t => t.Rows.Count); + } + }, cancellationToken, state).ConfigureAwait(false); - return BuildResult(result!); - } + return BuildResult(result!); + } - static Tuple, List, List, List, List> BuildResult(TableSet result) - { - if (result.Count != 5) - throw new DataException($"Expected 5 tables but received {result.Count} tables"); + static Tuple, List, List, List, List> BuildResult(TableSet result) + { + if (result.Count != 5) + throw new DataException($"Expected 5 tables but received {result.Count} tables"); - return Tuple.Create( - result[0].ToObjects().ToList(), - result[1].ToObjects().ToList(), - result[2].ToObjects().ToList(), - result[3].ToObjects().ToList(), - result[4].ToObjects().ToList() - ); - } + return Tuple.Create( + result[0].ToObjects().ToList(), + result[1].ToObjects().ToList(), + result[2].ToObjects().ToList(), + result[3].ToObjects().ToList(), + result[4].ToObjects().ToList() + ); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/DataSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/DataSetMaterializer`2.cs index e57f39272..e2089ca96 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/DataSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/DataSetMaterializer`2.cs @@ -2,80 +2,79 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a DataSet. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DataSetMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { + readonly string[] m_TableNames; + /// - /// Materializes the result set as a DataSet. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DataSetMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The table names. + public DataSetMaterializer(DbCommandBuilder commandBuilder, string[] tableNames) + : base(commandBuilder) { - readonly string[] m_TableNames; - - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The table names. - public DataSetMaterializer(DbCommandBuilder commandBuilder, string[] tableNames) - : base(commandBuilder) - { - m_TableNames = tableNames; - } + m_TableNames = tableNames; + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - public override DataSet Execute(object? state = null) - { - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - Prepare().Execute(cmd => + /// + /// Execute the operation synchronously. + /// + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + public override DataSet Execute(object? state = null) + { + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + Prepare().Execute(cmd => + { + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - ds.Load(reader, LoadOption.OverwriteChanges, m_TableNames); - return ds.Tables.Cast().Sum(t => t.Rows.Count); - } - }, state); + ds.Load(reader, LoadOption.OverwriteChanges, m_TableNames); + return ds.Tables.Cast().Sum(t => t.Rows.Count); + } + }, state); - return ds; - } + return ds; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + await Prepare().ExecuteAsync(async cmd => { - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - await Prepare().ExecuteAsync(async cmd => + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - ds.Load(reader, LoadOption.OverwriteChanges, m_TableNames); - return ds.Tables.Cast().Sum(t => t.Rows.Count); - } - }, cancellationToken, state).ConfigureAwait(false); + ds.Load(reader, LoadOption.OverwriteChanges, m_TableNames); + return ds.Tables.Cast().Sum(t => t.Rows.Count); + } + }, cancellationToken, state).ConfigureAwait(false); - return ds; - } + return ds; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/TableSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/TableSetMaterializer`2.cs index 1336fadca..155c5dda6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/TableSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/MultipleTable/TableSetMaterializer`2.cs @@ -1,87 +1,86 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TableSet. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TableSetMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// Materializes the result set as a TableSet. - /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TableSetMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter - { - readonly string[] m_TableNames; + readonly string[] m_TableNames; - /// Initializes a new instance of the class. - /// The command builder. - /// The table names. - public TableSetMaterializer(DbCommandBuilder commandBuilder, string[] tableNames) - : base(commandBuilder) - { - m_TableNames = tableNames; - } + /// Initializes a new instance of the class. + /// The command builder. + /// The table names. + public TableSetMaterializer(DbCommandBuilder commandBuilder, string[] tableNames) + : base(commandBuilder) + { + m_TableNames = tableNames; + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// - public override TableSet Execute(object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation synchronously. + /// + /// + public override TableSet Execute(object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); - executionToken.Execute(cmd => + var executionToken = Prepare(); + executionToken.Execute(cmd => + { + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - result = new TableSet(reader, m_TableNames); - return result.Sum(t => t.Rows.Count); - } - }, state); + result = new TableSet(reader, Converter, m_TableNames); + return result.Sum(t => t.Rows.Count); + } + }, state); - if (m_TableNames.Length > result!.Count) - throw new DataException($"Expected at least {m_TableNames.Length} tables but received {result.Count} tables"); + if (m_TableNames.Length > result!.Count) + throw new DataException($"Expected at least {m_TableNames.Length} tables but received {result.Count} tables"); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - TableSet? result = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + TableSet? result = null; - var executionToken = Prepare(); + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior).ConfigureAwait(false)) - { - result = new TableSet(reader, m_TableNames); - return result.Sum(t => t.Rows.Count); - } - }, cancellationToken, state).ConfigureAwait(false); + result = new TableSet(reader, Converter, m_TableNames); + return result.Sum(t => t.Rows.Count); + } + }, cancellationToken, state).ConfigureAwait(false); - if (m_TableNames.Length > result!.Count) - throw new DataException($"Expected at least {m_TableNames.Length} tables but received {result.Count} tables"); + if (m_TableNames.Length > result!.Count) + throw new DataException($"Expected at least {m_TableNames.Length} tables but received {result.Count} tables"); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/NonQueryMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/NonQueryMaterializer`2.cs index 2396716a3..f64009d03 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/NonQueryMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/NonQueryMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This class indicates the associated operation should be executed without returning a result set. +/// +public class NonQueryMaterializer : Materializer + where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The associated command builder. + public NonQueryMaterializer(DbCommandBuilder commandBuilder) + : base(commandBuilder) + { } + /// - /// This class indicates the associated operation should be executed without returning a result set. + /// Returns the list of columns the materializer would like to have. /// - public class NonQueryMaterializer : Materializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// Initializes a new instance of the class. - /// The associated command builder. - public NonQueryMaterializer(DbCommandBuilder commandBuilder) - : base(commandBuilder) - { } + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => NoColumns; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => NoColumns; - - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// Number of rows affected, if available from the database. - public override int? Execute(object? state = null) - { - return Prepare().Execute(cmd => cmd.ExecuteNonQuery(), state); - } + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// Number of rows affected, if available from the database. + public override int? Execute(object? state = null) + { + return Prepare().Execute(cmd => cmd.ExecuteNonQuery(), state); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Number of rows affected, if available from the database. - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Number of rows affected, if available from the database. + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + return await Prepare().ExecuteAsync(async cmd => { - return await Prepare().ExecuteAsync(async cmd => - { - return await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); - }, cancellationToken, state).ConfigureAwait(false); - } + return await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + }, cancellationToken, state).ConfigureAwait(false); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Operation`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Operation`2.cs index 1aeecbeb8..905fffd50 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Operation`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Operation`2.cs @@ -3,101 +3,100 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This is the operation equivalent to the NonQueryMaterializer. +/// +/// The type of the t connection. +/// The type of the t transaction. +public class Operation : ILink + where TConnection : DbConnection + where TTransaction : DbTransaction { + readonly DbOperationBuilder m_OperationBuilder; + /// - /// This is the operation equivalent to the NonQueryMaterializer. + /// Initializes a new instance of the class. /// - /// The type of the t connection. - /// The type of the t transaction. - public class Operation : ILink - where TConnection : DbConnection - where TTransaction : DbTransaction + /// The operation builder. + public Operation(DbOperationBuilder operationBuilder) { - readonly DbOperationBuilder m_OperationBuilder; - - /// - /// Initializes a new instance of the class. - /// - /// The operation builder. - public Operation(DbOperationBuilder operationBuilder) - { - m_OperationBuilder = operationBuilder; - } - - /// - /// Occurs when an execution token has been prepared. - /// - /// This is mostly used by appenders to override command behavior. - public event EventHandler? ExecutionTokenPrepared; - - /// - /// Occurs when an execution token is about to be prepared. - /// - /// This is mostly used by appenders to override SQL generation. - public event EventHandler? ExecutionTokenPreparing; - - /// - /// Gets the data source that is associated with this materializer or appender. - /// - /// The data source. - /// This is only used for - public IDataSource DataSource => m_OperationBuilder.DataSource; + m_OperationBuilder = operationBuilder; + } + + /// + /// Occurs when an execution token has been prepared. + /// + /// This is mostly used by appenders to override command behavior. + public event EventHandler? ExecutionTokenPrepared; + + /// + /// Occurs when an execution token is about to be prepared. + /// + /// This is mostly used by appenders to override SQL generation. + public event EventHandler? ExecutionTokenPreparing; + + /// + /// Gets the data source that is associated with this materializer or appender. + /// + /// The data source. + /// This is only used for + public IDataSource DataSource => m_OperationBuilder.DataSource; #pragma warning disable CA1033 // Interface methods should be callable by child types - string? ILink.CommandText() => null; + string? ILink.CommandText() => null; #pragma warning restore CA1033 // Interface methods should be callable by child types - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// System.Nullable<System.Int32>. - public int? Execute(object? state = null) - { - var token = Prepare(); - OperationImplementation implementation = m_OperationBuilder.Implementation; - return token.Execute(implementation, state); - } - - /// - /// Execute the operation asynchronously. - /// - /// User defined state, usually used for logging. - /// Task<System.Nullable<System.Int32>>. - public Task ExecuteAsync(object? state = null) - { - return ExecuteAsync(CancellationToken.None, state); - } - - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task<System.Nullable<System.Int32>>. - public Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var token = Prepare(); - OperationImplementationAsync implementation = m_OperationBuilder.ImplementationAsync; - return token.ExecuteAsync(implementation, cancellationToken, state); - } - - /// - /// Prepares this operation for execution. - /// - /// ExecutionToken<TCommand, TParameter>. - protected OperationExecutionToken Prepare() - { - ExecutionTokenPreparing?.Invoke(this, new ExecutionTokenPreparingEventArgs(m_OperationBuilder)); - - var executionToken = m_OperationBuilder.Prepare(); - - ExecutionTokenPrepared?.Invoke(this, new ExecutionTokenPreparedEventArgs(executionToken)); - - return executionToken; - } + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// System.Nullable<System.Int32>. + public int? Execute(object? state = null) + { + var token = Prepare(); + OperationImplementation implementation = m_OperationBuilder.Implementation; + return token.Execute(implementation, state); + } + + /// + /// Execute the operation asynchronously. + /// + /// User defined state, usually used for logging. + /// Task<System.Nullable<System.Int32>>. + public Task ExecuteAsync(object? state = null) + { + return ExecuteAsync(CancellationToken.None, state); + } + + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task<System.Nullable<System.Int32>>. + public Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var token = Prepare(); + OperationImplementationAsync implementation = m_OperationBuilder.ImplementationAsync; + return token.ExecuteAsync(implementation, cancellationToken, state); + } + + /// + /// Prepares this operation for execution. + /// + /// ExecutionToken<TCommand, TParameter>. + protected OperationExecutionToken Prepare() + { + ExecutionTokenPreparing?.Invoke(this, new ExecutionTokenPreparingEventArgs(m_OperationBuilder)); + + var executionToken = m_OperationBuilder.Prepare(); + + ExecutionTokenPrepared?.Invoke(this, new ExecutionTokenPreparedEventArgs(executionToken)); + + return executionToken; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/OrdinalMappedProperty`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/OrdinalMappedProperty`1.cs index 69b75b062..742d8f658 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/OrdinalMappedProperty`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/OrdinalMappedProperty`1.cs @@ -1,24 +1,23 @@ using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal class OrdinalMappedProperty + where TTarget : class { - internal class OrdinalMappedProperty - where TTarget : class - { - readonly MappedProperty m_MappedProperty; + readonly MappedProperty m_MappedProperty; - public OrdinalMappedProperty(MappedProperty mappedProperty, int ordinal) - { - m_MappedProperty = mappedProperty; - Ordinal = ordinal; - } + public OrdinalMappedProperty(MappedProperty mappedProperty, int ordinal) + { + m_MappedProperty = mappedProperty; + Ordinal = ordinal; + } - public string MappedColumnName => m_MappedProperty.MappedColumnName; + public string MappedColumnName => m_MappedProperty.MappedColumnName; - public int Ordinal { get; } + public int Ordinal { get; } - public PropertyMetadata PropertyMetadata => m_MappedProperty.PropertyMetadata; + public PropertyMetadata PropertyMetadata => m_MappedProperty.PropertyMetadata; - public void InvokeSet(TTarget target, object value) => m_MappedProperty.InvokeSet(target, value); - } + public void InvokeSet(TTarget target, object value) => m_MappedProperty.InvokeSet(target, value); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanMaterializer`2.cs index daa156c8a..f2aede8f2 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanMaterializer`2.cs @@ -2,57 +2,56 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a boolean. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class BooleanMaterializer : ScalarMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a boolean. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class BooleanMaterializer : ScalarMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public BooleanMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public BooleanMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - /// - /// Unexpected null result - public override bool Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + /// + /// Unexpected null result + public override bool Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); - } + return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// Unexpected null result - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// Unexpected null result + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); - } + return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanOrNullMaterializer`2.cs index 0005260f7..0265adec3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/BooleanOrNullMaterializer`2.cs @@ -2,54 +2,53 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a boolean. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class BooleanOrNullMaterializer : ScalarMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a boolean. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class BooleanOrNullMaterializer : ScalarMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public BooleanOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public BooleanOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override bool? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override bool? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); - } + return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); - } + return Convert.ToBoolean(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayMaterializer`2.cs index bb28d1984..4ce185efb 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a byte array. +/// +/// The type of the tt command type. +/// The type of the t parameter type. +internal sealed class ByteArrayMaterializer : ScalarMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a byte array. + /// Initializes a new instance of the class. /// - /// The type of the tt command type. - /// The type of the t parameter type. - internal sealed class ByteArrayMaterializer : ScalarMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public ByteArrayMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public ByteArrayMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override byte[] Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + public override byte[] Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (byte[])temp; - } + return (byte[])temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (byte[])temp; - } + return (byte[])temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayOrNullMaterializer`2.cs index c11545a0e..eb102b3d6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteArrayOrNullMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a byte array. +/// +/// The type of the tt command type. +/// The type of the t parameter type. +internal sealed class ByteArrayOrNullMaterializer : ScalarMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a byte array. + /// Initializes a new instance of the class. /// - /// The type of the tt command type. - /// The type of the t parameter type. - internal sealed class ByteArrayOrNullMaterializer : ScalarMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public ByteArrayOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public ByteArrayOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override byte[]? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override byte[]? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return (byte[])temp; - } + return (byte[])temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return (byte[])temp; - } + return (byte[])temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteMaterializer`2.cs index 8c1ad2230..d0b59ba88 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteMaterializer`2.cs @@ -2,57 +2,56 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a byte. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class ByteMaterializer : ScalarMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a byte. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class ByteMaterializer : ScalarMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public ByteMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public ByteMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - /// - /// Unexpected null result - public override byte Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + /// + /// Unexpected null result + public override byte Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToByte(temp, CultureInfo.InvariantCulture); - } + return Convert.ToByte(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// Unexpected null result - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// Unexpected null result + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToByte(temp, CultureInfo.InvariantCulture); - } + return Convert.ToByte(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteOrNullMaterializer`2.cs index 733b25e69..712adb875 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/ByteOrNullMaterializer`2.cs @@ -2,54 +2,53 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a byte. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class ByteOrNullMaterializer : ScalarMaterializer + where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a byte. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class ByteOrNullMaterializer : ScalarMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public ByteOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public ByteOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override byte? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override byte? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToByte(temp, CultureInfo.InvariantCulture); - } + return Convert.ToByte(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToByte(temp, CultureInfo.InvariantCulture); - } + return Convert.ToByte(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeMaterializer`2.cs index ad0189563..a7deab303 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a DateTime. +/// +/// The type of the tt command type. +/// The type of the t parameter type. +internal sealed class DateTimeMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter + { /// - /// Materializes the result set as a DateTime. + /// Initializes a new instance of the class. /// - /// The type of the tt command type. - /// The type of the t parameter type. - internal sealed class DateTimeMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + public DateTimeMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// + /// Execute the operation synchronously. + /// + /// + public override DateTime Execute(object? state = null) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DateTimeMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } - - /// - /// Execute the operation synchronously. - /// - /// - public override DateTime Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (DateTime)temp; - } + return (DateTime)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (DateTime)temp; - } + return (DateTime)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetMaterializer`2.cs index 05980a781..e97282ac0 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a DateTimeOffset. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOffsetMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter + { /// - /// Materializes the result set as a DateTimeOffset. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOffsetMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + public DateTimeOffsetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// + /// Execute the operation synchronously. + /// + /// + public override DateTimeOffset Execute(object? state = null) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DateTimeOffsetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } - - /// - /// Execute the operation synchronously. - /// - /// - public override DateTimeOffset Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (DateTimeOffset)temp; - } + return (DateTimeOffset)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (DateTimeOffset)temp; - } + return (DateTimeOffset)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetOrNullMaterializer`2.cs index 1b77b16df..e6533a676 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOffsetOrNullMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a DateTimeOffset. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOffsetOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter + { /// - /// Materializes the result set as a DateTimeOffset. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOffsetOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + public DateTimeOffsetOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// + /// Execute the operation synchronously. + /// + /// + public override DateTimeOffset? Execute(object? state = null) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DateTimeOffsetOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } - - /// - /// Execute the operation synchronously. - /// - /// - public override DateTimeOffset? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return (DateTimeOffset)temp; - } + return (DateTimeOffset)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return (DateTimeOffset)temp; - } + return (DateTimeOffset)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOrNullMaterializer`2.cs index af7d22220..69072270b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DateTimeOrNullMaterializer`2.cs @@ -1,54 +1,53 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a DateTime. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter + { /// - /// Materializes the result set as a DateTime. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + public DateTimeOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// + /// Execute the operation synchronously. + /// + /// + public override DateTime? Execute(object? state = null) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DateTimeOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } - - /// - /// Execute the operation synchronously. - /// - /// - public override DateTime? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return (DateTime)temp; - } + return (DateTime)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return (DateTime)temp; - } + return (DateTime)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalMaterializer`2.cs index b4ad98525..93e94a718 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalMaterializer`2.cs @@ -2,53 +2,52 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a decimal. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DecimalMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a decimal. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DecimalMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DecimalMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public DecimalMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override decimal Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + public override decimal Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalOrNullMaterializer`2.cs index 769dc5a4c..d6f846c83 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DecimalOrNullMaterializer`2.cs @@ -2,54 +2,53 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a decimal. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DecimalOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter + { /// - /// Materializes the result set as a decimal. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DecimalOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + public DecimalOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// + /// Execute the operation synchronously. + /// + /// + public override decimal? Execute(object? state = null) { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DecimalOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } - - /// - /// Execute the operation synchronously. - /// - /// - public override decimal? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDecimal(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleMaterializer`2.cs index adce09a76..8168d8b0b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleMaterializer`2.cs @@ -2,55 +2,54 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a floating point number. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DoubleMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a floating point number. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DoubleMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public DoubleMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public DoubleMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - /// - /// Unexpected null result - public override double Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + /// + /// Unexpected null result + public override double Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToDouble(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDouble(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - /// Unexpected null result - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + /// Unexpected null result + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToDouble(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDouble(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleOrNullMaterializer`2.cs index 221f30a00..a6828f561 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/DoubleOrNullMaterializer`2.cs @@ -2,53 +2,52 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a floating point number. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DoubleOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a floating point number. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DoubleOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public DoubleOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public DoubleOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override double? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override double? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToDouble(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDouble(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToDouble(temp, CultureInfo.InvariantCulture); - } + return Convert.ToDouble(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidMaterializer`2.cs index 047ea1dd5..0c3902886 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidMaterializer`2.cs @@ -1,51 +1,50 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a Guid. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class GuidMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The command builder. + /// Name of the desired column. + public GuidMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// - /// Materializes the result set as a Guid. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class GuidMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// + public override Guid Execute(object? state = null) { - /// Initializes a new instance of the class. - /// The command builder. - /// Name of the desired column. - public GuidMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - /// - /// Execute the operation synchronously. - /// - /// - public override Guid Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); - - return (Guid)temp; - } + return (Guid)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (Guid)temp; - } + return (Guid)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidOrNullMaterializer`2.cs index 1cfde6600..2865aa7f9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/GuidOrNullMaterializer`2.cs @@ -1,52 +1,51 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a Guid. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class GuidOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a Guid. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class GuidOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public GuidOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public GuidOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override Guid? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override Guid? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return (Guid)temp; - } + return (Guid)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return (Guid)temp; - } + return (Guid)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16Materializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16Materializer`2.cs index dc6fa3d83..f1582c54f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16Materializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16Materializer`2.cs @@ -2,52 +2,51 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an integer. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int16Materializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as an integer. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int16Materializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public Int16Materializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public Int16Materializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override short Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + public override short Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToInt16(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt16(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToInt16(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt16(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16OrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16OrNullMaterializer`2.cs index 625c1a015..6c4e94893 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16OrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int16OrNullMaterializer`2.cs @@ -2,52 +2,51 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an integer. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int16OrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as an integer. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int16OrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public Int16OrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public Int16OrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override short? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override short? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToInt16(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt16(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToInt16(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt16(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32Materializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32Materializer`2.cs index 2f09d0f4d..43177376d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32Materializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32Materializer`2.cs @@ -2,52 +2,51 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an integer. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int32Materializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as an integer. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int32Materializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public Int32Materializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public Int32Materializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override int Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + public override int Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToInt32(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt32(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToInt32(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt32(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32OrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32OrNullMaterializer`2.cs index fcd40176b..2ab780fbc 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32OrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int32OrNullMaterializer`2.cs @@ -2,52 +2,51 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an integer. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int32OrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as an integer. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int32OrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public Int32OrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public Int32OrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override int? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override int? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToInt32(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt32(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToInt32(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt32(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64Materializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64Materializer`2.cs index dd5a9ea86..424974e6b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64Materializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64Materializer`2.cs @@ -2,53 +2,52 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an integer. +/// +/// The type of the tt command type. +/// The type of the t parameter type. +internal sealed class Int64Materializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as an integer. + /// Initializes a new instance of the class. /// - /// The type of the tt command type. - /// The type of the t parameter type. - internal sealed class Int64Materializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public Int64Materializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public Int64Materializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override long Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + public override long Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToInt64(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt64(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToInt64(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt64(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64OrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64OrNullMaterializer`2.cs index db2eceacd..d3d7d17c8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64OrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/Int64OrNullMaterializer`2.cs @@ -2,51 +2,50 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an integer. +/// +/// The type of the tt command type. +/// The type of the t parameter type. +internal sealed class Int64OrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The command builder. + /// Name of the desired column. + public Int64OrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// - /// Materializes the result set as an integer. + /// Execute the operation synchronously. /// - /// The type of the tt command type. - /// The type of the t parameter type. - internal sealed class Int64OrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// + public override long? Execute(object? state = null) { - /// Initializes a new instance of the class. - /// The command builder. - /// Name of the desired column. - public Int64OrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - /// - /// Execute the operation synchronously. - /// - /// - public override long? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; - - return Convert.ToInt64(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt64(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToInt64(temp, CultureInfo.InvariantCulture); - } + return Convert.ToInt64(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleColumnMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleColumnMaterializer`3.cs index aaae877d1..9b34ef05c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleColumnMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleColumnMaterializer`3.cs @@ -3,89 +3,88 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This class represents result materializers that read a Scalar value. +/// +public abstract class ScalarMaterializer : Materializer + where TCommand : DbCommand + where TParameter : DbParameter { + readonly string? m_DesiredColumn; + /// - /// This class represents result materializers that read a Scalar value. + /// Initializes a new instance of the class. /// - public abstract class ScalarMaterializer : Materializer - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + protected ScalarMaterializer(DbCommandBuilder commandBuilder, string? columnName) + : base(commandBuilder) { - readonly string? m_DesiredColumn; - - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - protected ScalarMaterializer(DbCommandBuilder commandBuilder, string? columnName) - : base(commandBuilder) - { - m_DesiredColumn = columnName; - } + m_DesiredColumn = columnName; + } - /// - /// Returns the list of columns the result materializer would like to have. - /// - public override IReadOnlyList DesiredColumns() - { - if (m_DesiredColumn != null) - return ImmutableArray.Create(m_DesiredColumn); - else - return base.DesiredColumns(); - } + /// + /// Returns the list of columns the result materializer would like to have. + /// + public override IReadOnlyList DesiredColumns() + { + if (m_DesiredColumn != null) + return ImmutableArray.Create(m_DesiredColumn); + else + return base.DesiredColumns(); + } - /// - /// Helper method for executing the operation. - /// - /// The implementation. - /// The state. - protected void ExecuteCore(CommandImplementation implementation, object? state) - { - Prepare().Execute(implementation, state); - } + /// + /// Helper method for executing the operation. + /// + /// The implementation. + /// The state. + protected void ExecuteCore(CommandImplementation implementation, object? state) + { + Prepare().Execute(implementation, state); + } - /// - /// Helper method for executing the operation. - /// - /// The implementation. - /// The state. - protected void ExecuteCore(Action implementation, object? state) + /// + /// Helper method for executing the operation. + /// + /// The implementation. + /// The state. + protected void ExecuteCore(Action implementation, object? state) + { + Prepare().Execute(cmd => { - Prepare().Execute(cmd => - { - implementation(cmd); - return null; - }, state); - } + implementation(cmd); + return null; + }, state); + } - /// - /// Helper method for executing the operation. - /// - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected Task ExecuteCoreAsync(CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - return Prepare().ExecuteAsync(implementation, cancellationToken, state); - } + /// + /// Helper method for executing the operation. + /// + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected Task ExecuteCoreAsync(CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + return Prepare().ExecuteAsync(implementation, cancellationToken, state); + } - /// - /// Helper method for executing the operation. - /// - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected Task ExecuteCoreAsync(Func implementation, CancellationToken cancellationToken, object? state) + /// + /// Helper method for executing the operation. + /// + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected Task ExecuteCoreAsync(Func implementation, CancellationToken cancellationToken, object? state) + { + return Prepare().ExecuteAsync(async cmd => { - return Prepare().ExecuteAsync(async cmd => - { - await implementation(cmd).ConfigureAwait(false); - return null; - }, cancellationToken, state); - } + await implementation(cmd).ConfigureAwait(false); + return null; + }, cancellationToken, state); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleMaterializer`2.cs index 2a7064d7f..cbcbf49ba 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleMaterializer`2.cs @@ -2,53 +2,52 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a floating point number. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class SingleMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a floating point number. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class SingleMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public SingleMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public SingleMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override float Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// + public override float Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToSingle(temp, CultureInfo.InvariantCulture); - } + return Convert.ToSingle(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return Convert.ToSingle(temp, CultureInfo.InvariantCulture); - } + return Convert.ToSingle(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleOrNullMaterializer`2.cs index ed3e43476..3331a2bfc 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/SingleOrNullMaterializer`2.cs @@ -2,52 +2,51 @@ using System.Globalization; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a floating point number. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class SingleOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a floating point number. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class SingleOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public SingleOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public SingleOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override float? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override float? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToSingle(temp, CultureInfo.InvariantCulture); - } + return Convert.ToSingle(temp, CultureInfo.InvariantCulture); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return Convert.ToSingle(temp, CultureInfo.InvariantCulture); - } + return Convert.ToSingle(temp, CultureInfo.InvariantCulture); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringMaterializer`2.cs index 10ca8746b..4ad8c155d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringMaterializer`2.cs @@ -1,51 +1,50 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a string. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class StringMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The command builder. + /// Name of the desired column. + public StringMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// - /// Materializes the result set as a string. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class StringMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// + public override string Execute(object? state = null) { - /// Initializes a new instance of the class. - /// The command builder. - /// Name of the desired column. - public StringMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - /// - /// Execute the operation synchronously. - /// - /// - public override string Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); - - return (string)temp; - } + return (string)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (string)temp; - } + return (string)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringOrNullMaterializer`2.cs index baff70496..7fb60bde4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/StringOrNullMaterializer`2.cs @@ -1,51 +1,50 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a string. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class StringMaterializerOrNull : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The command builder. + /// Name of the desired column. + public StringMaterializerOrNull(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// - /// Materializes the result set as a string. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class StringMaterializerOrNull : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// + public override string? Execute(object? state = null) { - /// Initializes a new instance of the class. - /// The command builder. - /// Name of the desired column. - public StringMaterializerOrNull(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == DBNull.Value) + return null; - /// - /// Execute the operation synchronously. - /// - /// - public override string? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == DBNull.Value) - return null; - - return (string?)temp; - } + return (string?)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == DBNull.Value) + return null; - return (string?)temp; - } + return (string?)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanMaterializer`2.cs index a0cdbbd86..4df78d994 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanMaterializer`2.cs @@ -1,56 +1,55 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TimeSpan. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TimeSpanMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a TimeSpan. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TimeSpanMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - public TimeSpanMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public TimeSpanMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// The state. - /// TimeSpan. - /// Unexpected null result - public override TimeSpan Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation synchronously. + /// + /// The state. + /// TimeSpan. + /// Unexpected null result + public override TimeSpan Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (TimeSpan)temp; - } + return (TimeSpan)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task<TimeSpan>. - /// Unexpected null result - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task<TimeSpan>. + /// Unexpected null result + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return (TimeSpan)temp; - } + return (TimeSpan)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanOrNullMaterializer`2.cs index c4c20f48c..33763e4b3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/TimeSpanOrNullMaterializer`2.cs @@ -1,52 +1,51 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a TimeSpan. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TimeSpanOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { /// - /// Materializes the result set as a TimeSpan. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TimeSpanOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter - { - /// - /// - /// The command builder. - /// Name of the desired column. - public TimeSpanOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + /// The command builder. + /// Name of the desired column. + public TimeSpanOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } - /// - /// Execute the operation synchronously. - /// - /// - public override TimeSpan? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation synchronously. + /// + /// + public override TimeSpan? Execute(object? state = null) + { + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - return (TimeSpan)temp; - } + return (TimeSpan)temp; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return (TimeSpan)temp; - } + return (TimeSpan)temp; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementMaterializer`2.cs index 5919489f3..d32499064 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementMaterializer`2.cs @@ -2,51 +2,50 @@ using System.Xml.Linq; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a string. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class XElementMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The command builder. + /// Name of the desired column. + public XElementMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// - /// Materializes the result set as a string. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class XElementMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// + public override XElement Execute(object? state = null) { - /// Initializes a new instance of the class. - /// The command builder. - /// Name of the desired column. - public XElementMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - /// - /// Execute the operation synchronously. - /// - /// - public override XElement Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); - - return XElement.Parse((string)temp); - } + return XElement.Parse((string)temp); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - throw new MissingDataException("Unexpected null result"); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + throw new MissingDataException("Unexpected null result"); - return XElement.Parse((string)temp); - } + return XElement.Parse((string)temp); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementOrNullMaterializer`2.cs index c51ee278b..541c07906 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/Scalar/XElementOrNullMaterializer`2.cs @@ -2,51 +2,50 @@ using System.Xml.Linq; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an XElement. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class XElementOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand + where TParameter : DbParameter { + /// Initializes a new instance of the class. + /// The command builder. + /// Name of the desired column. + public XElementOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) + : base(commandBuilder, columnName) + { } + /// - /// Materializes the result set as an XElement. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class XElementOrNullMaterializer : ScalarMaterializer where TCommand : DbCommand - where TParameter : DbParameter + /// + public override XElement? Execute(object? state = null) { - /// Initializes a new instance of the class. - /// The command builder. - /// Name of the desired column. - public XElementOrNullMaterializer(DbCommandBuilder commandBuilder, string? columnName = null) - : base(commandBuilder, columnName) - { } + object? temp = null; + ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); + if (temp == null || temp == DBNull.Value) + return null; - /// - /// Execute the operation synchronously. - /// - /// - public override XElement? Execute(object? state = null) - { - object? temp = null; - ExecuteCore(cmd => temp = cmd.ExecuteScalar(), state); - if (temp == null || temp == DBNull.Value) - return null; - - return XElement.Parse((string)temp); - } + return XElement.Parse((string)temp); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - object? temp = null; - await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); - if (temp == null || temp == DBNull.Value) - return null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + object? temp = null; + await ExecuteCoreAsync(async cmd => temp = await cmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state).ConfigureAwait(false); + if (temp == null || temp == DBNull.Value) + return null; - return XElement.Parse((string)temp); - } + return XElement.Parse((string)temp); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanListMaterializer`2.cs index d162f21e6..59f71dc21 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of booleans. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class BooleanListMaterializer : SingleColumnMaterializer> + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of booleans. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class BooleanListMaterializer : SingleColumnMaterializer> - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public BooleanListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public BooleanListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetBoolean(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetBoolean(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetBoolean(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetBoolean(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanOrNullListMaterializer`2.cs index ce0f17ec6..5ff785201 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/BooleanOrNullListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of booleans. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class BooleanOrNullListMaterializer : SingleColumnMaterializer> + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of booleans. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class BooleanOrNullListMaterializer : SingleColumnMaterializer> - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public BooleanOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public BooleanOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetBoolean(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetBoolean(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetBoolean(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetBoolean(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayListMaterializer`2.cs index 048260a3f..6975a7ff6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of byte arrays. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class ByteArrayListMaterializer : SingleColumnMaterializer> + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of byte arrays. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class ByteArrayListMaterializer : SingleColumnMaterializer> - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public ByteArrayListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public ByteArrayListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((byte[])reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((byte[])reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((byte[])reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((byte[])reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayOrNullListMaterializer`2.cs index ba3044b06..ba1b3f441 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteArrayOrNullListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of byte arrays. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class ByteArrayOrNullListMaterializer : SingleColumnMaterializer> + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of byte arrays. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class ByteArrayOrNullListMaterializer : SingleColumnMaterializer> - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public ByteArrayOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public ByteArrayOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((byte[])reader.GetValue(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add((byte[])reader.GetValue(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((byte[])reader.GetValue(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add((byte[])reader.GetValue(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteListMaterializer`2.cs index 51e31f0e0..3d115c15c 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of byte. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class ByteListMaterializer : SingleColumnMaterializer> + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of byte. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class ByteListMaterializer : SingleColumnMaterializer> - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public ByteListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public ByteListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetByte(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetByte(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetByte(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetByte(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteOrNullListMaterializer`2.cs index e08d43655..a00ba2c43 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/ByteOrNullListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of byte. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class ByteOrNullListMaterializer : SingleColumnMaterializer> + where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of byte. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class ByteOrNullListMaterializer : SingleColumnMaterializer> - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public ByteOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public ByteOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetByte(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetByte(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetByte(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetByte(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeListMaterializer`2.cs index 55c076ccd..f8f8e22df 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of DateTime. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of DateTime. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DateTimeListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DateTimeListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDateTime(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDateTime(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDateTime(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDateTime(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListMaterializer`2.cs index ad2cb23ef..e66b9de93 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of DateTimeOffset. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOffsetListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of DateTimeOffset. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOffsetListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DateTimeOffsetListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DateTimeOffsetListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((DateTimeOffset)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((DateTimeOffset)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((DateTimeOffset)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((DateTimeOffset)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListOrNullMaterializer`2.cs index 6186a9c82..af86cfd20 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetListOrNullMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of DateTimeOffset. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOffsetOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of DateTimeOffset. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOffsetOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DateTimeOffsetOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DateTimeOffsetOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((DateTimeOffset)reader.GetValue(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add((DateTimeOffset)reader.GetValue(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((DateTimeOffset)reader.GetValue(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add((DateTimeOffset)reader.GetValue(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetSetMaterializer`2.cs index b4afe3fb2..46612a7eb 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOffsetSetMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of DateTimeOffset. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOffsetSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of DateTimeOffset. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOffsetSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DateTimeOffsetSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DateTimeOffsetSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((DateTimeOffset)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((DateTimeOffset)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((DateTimeOffset)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((DateTimeOffset)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOrNullListMaterializer`2.cs index 35aca61ee..86a26f76e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeOrNullListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of DateTime. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of DateTime. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DateTimeOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DateTimeOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDateTime(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDateTime(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDateTime(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDateTime(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeSetMaterializer`2.cs index e57ac93f8..2f5674114 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DateTimeSetMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a set of DateTime. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DateTimeSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a set of DateTime. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DateTimeSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DateTimeSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DateTimeSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDateTime(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDateTime(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDateTime(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDateTime(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalListMaterializer`2.cs index 8b5ab50f0..2703db552 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DecimalListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DecimalListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DecimalListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DecimalListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDecimal(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDecimal(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDecimal(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDecimal(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalOrNullListMaterializer`2.cs index 9b85af158..498033f8e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalOrNullListMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DecimalOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DecimalOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DecimalOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DecimalOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDecimal(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDecimal(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDecimal(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDecimal(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalSetMaterializer`2.cs index 460ab357d..c8b6bea18 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DecimalSetMaterializer`2.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DecimalSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter + { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DecimalSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter - + /// The command builder. + /// The list options. + /// Name of the desired column. + public DecimalSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DecimalSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDecimal(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDecimal(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDecimal(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDecimal(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleListMaterializer`2.cs index 1f4ef9fd5..af1d02720 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleListMaterializer`2.cs @@ -1,107 +1,106 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DoubleListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DoubleListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public DoubleListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DoubleListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDouble(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDouble(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDouble(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDouble(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleOrNullListMaterializer`2.cs index b793b76ef..389d4d7a4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleOrNullListMaterializer`2.cs @@ -1,107 +1,106 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DoubleOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DoubleOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public DoubleOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DoubleOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDouble(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDouble(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDouble(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDouble(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleSetMaterializer`2.cs index 72138f718..6b418ed21 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/DoubleSetMaterializer`2.cs @@ -1,107 +1,106 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DoubleSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DoubleSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public DoubleSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public DoubleSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDouble(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDouble(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - { - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - } + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + } - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetDouble(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetDouble(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidListMaterializer`2.cs index 417c768af..661ca0529 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidListMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of Guids. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class GuidListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of Guids. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class GuidListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public GuidListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public GuidListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetGuid(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetGuid(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetGuid(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetGuid(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidOrNullListMaterializer`2.cs index aaee62540..f20232e31 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidOrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of Guids. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class GuidOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of Guids. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class GuidOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public GuidOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public GuidOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetGuid(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetGuid(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetGuid(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetGuid(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidSetMaterializer`2.cs index 73629e13b..fb54f3f05 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/GuidSetMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of Guids. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class GuidSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of Guids. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class GuidSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public GuidSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public GuidSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetGuid(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetGuid(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetGuid(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetGuid(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16ListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16ListMaterializer`2.cs index ea543cb1d..d161c8446 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16ListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16ListMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int16ListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int16ListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public Int16ListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public Int16ListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt16(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt16(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt16(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt16(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16OrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16OrNullListMaterializer`2.cs index 3564c3c12..ae5d19436 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16OrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16OrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int16OrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int16OrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public Int16OrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public Int16OrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt16(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt16(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt16(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt16(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16SetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16SetMaterializer`2.cs index f7aaba59f..8aa8175a3 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16SetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int16SetMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int16SetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int16SetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public Int16SetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public Int16SetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt16(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt16(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt16(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt16(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32ListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32ListMaterializer`2.cs index fb7d34ea9..9f287aa28 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32ListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32ListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int32ListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int32ListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public Int32ListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public Int32ListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt32(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt32(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt32(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt32(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32OrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32OrNullListMaterializer`2.cs index 9b228a86b..7c0bbab30 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32OrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32OrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int32OrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int32OrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public Int32OrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public Int32OrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt32(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt32(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt32(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt32(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32SetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32SetMaterializer`2.cs index bfa5c1e00..3a32b68fb 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32SetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int32SetMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int32SetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int32SetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public Int32SetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public Int32SetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt32(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt32(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt32(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt32(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64ListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64ListMaterializer`2.cs index b4097fb19..bff274dc8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64ListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64ListMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int64ListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int64ListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public Int64ListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public Int64ListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt64(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt64(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt64(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt64(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64OrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64OrNullListMaterializer`2.cs index d6590501f..84f34a762 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64OrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64OrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int64OrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int64OrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public Int64OrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public Int64OrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt64(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt64(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt64(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt64(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64SetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64SetMaterializer`2.cs index fb1d03a90..1896dd37d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64SetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/Int64SetMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of integers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class Int64SetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of integers. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class Int64SetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public Int64SetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public Int64SetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt64(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt64(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetInt64(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetInt64(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleColumnMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleColumnMaterializer`3.cs index c370b08e2..a642c66b9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleColumnMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleColumnMaterializer`3.cs @@ -2,37 +2,36 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// This class represents result materializers that read from a single column. +/// +public abstract class SingleColumnMaterializer : Materializer + where TCommand : DbCommand + where TParameter : DbParameter { + readonly string? m_DesiredColumn; + /// - /// This class represents result materializers that read from a single column. + /// Initializes a new instance of the class. /// - public abstract class SingleColumnMaterializer : Materializer - where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + protected SingleColumnMaterializer(DbCommandBuilder commandBuilder, string? columnName) + : base(commandBuilder) { - readonly string? m_DesiredColumn; - - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - protected SingleColumnMaterializer(DbCommandBuilder commandBuilder, string? columnName) - : base(commandBuilder) - { - m_DesiredColumn = columnName; - } + m_DesiredColumn = columnName; + } - /// - /// Returns the list of columns the result materializer would like to have. - /// - public override IReadOnlyList DesiredColumns() - { - if (m_DesiredColumn != null) - return ImmutableArray.Create(m_DesiredColumn); - else - return base.DesiredColumns(); - } + /// + /// Returns the list of columns the result materializer would like to have. + /// + public override IReadOnlyList DesiredColumns() + { + if (m_DesiredColumn != null) + return ImmutableArray.Create(m_DesiredColumn); + else + return base.DesiredColumns(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleListMaterializer`2.cs index e7817eeb9..f8b835704 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleListMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class SingleListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class SingleListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public SingleListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public SingleListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetFloat(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetFloat(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetFloat(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetFloat(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleOrNullListMaterializer`2.cs index 9ada9529d..d6fd4dfdd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleOrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class SingleOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class SingleOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public SingleOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public SingleOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetFloat(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetFloat(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetFloat(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetFloat(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleSetMaterializer`2.cs index 7f92a5b33..5c0172455 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/SingleSetMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of numbers. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class SingleSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of numbers. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class SingleSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public SingleSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public SingleSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetFloat(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetFloat(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetFloat(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetFloat(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringListMaterializer`2.cs index d90e025df..ad64184c1 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of strings. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class StringListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of strings. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class StringListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public StringListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public StringListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetString(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetString(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetString(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetString(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringOrNullListMaterializer`2.cs index 9789a1b65..db06da66f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringOrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of strings. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class StringOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of strings. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class StringOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public StringOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public StringOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetString(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetString(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetString(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetString(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringSetMaterializer`2.cs index 38ca0417d..b189ea82b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/StringSetMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of strings. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class StringSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of strings. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class StringSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public StringSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public StringSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetString(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetString(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(reader.GetString(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(reader.GetString(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanListMaterializer`2.cs index 6ccf146ed..6fc38e6d9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanListMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of TimeSpan. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TimeSpanListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of TimeSpan. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TimeSpanListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public TimeSpanListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public TimeSpanListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((TimeSpan)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((TimeSpan)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((TimeSpan)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((TimeSpan)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanOrNullListMaterializer`2.cs index a839f4070..c128c4289 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanOrNullListMaterializer`2.cs @@ -1,103 +1,102 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of TimeSpan. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TimeSpanOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of TimeSpan. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TimeSpanOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public TimeSpanOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public TimeSpanOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((TimeSpan)reader.GetValue(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add((TimeSpan)reader.GetValue(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((TimeSpan)reader.GetValue(i)); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add((TimeSpan)reader.GetValue(i)); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanSetMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanSetMaterializer`2.cs index 02ae9ee36..89d98a3d0 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanSetMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/TimeSpanSetMaterializer`2.cs @@ -1,102 +1,101 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of TimeSpan. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class TimeSpanSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of TimeSpan. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class TimeSpanSetMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// The list options. + /// Name of the desired column. + public TimeSpanSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// - /// The command builder. - /// The list options. - /// Name of the desired column. - public TimeSpanSetMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override HashSet Execute(object? state = null) + { + var result = new HashSet(); - /// - /// Execute the operation synchronously. - /// - /// - public override HashSet Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new HashSet(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((TimeSpan)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((TimeSpan)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new HashSet(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new HashSet(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add((TimeSpan)reader.GetValue(i)); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add((TimeSpan)reader.GetValue(i)); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementListMaterializer`2.cs index 5676c54fb..df9a30aa7 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementListMaterializer`2.cs @@ -2,103 +2,102 @@ using System.Xml.Linq; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of strings. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class XElementListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of strings. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class XElementListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public XElementListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public XElementListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(XElement.Parse(reader.GetString(i))); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(XElement.Parse(reader.GetString(i))); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(XElement.Parse(reader.GetString(i))); - else if (!discardNulls) - throw new MissingDataException("Unexpected null value"); - } + if (!reader.IsDBNull(i)) + result.Add(XElement.Parse(reader.GetString(i))); + else if (!discardNulls) + throw new MissingDataException("Unexpected null value"); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementOrNullListMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementOrNullListMaterializer`2.cs index 7bfee7fd5..6336c51b9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementOrNullListMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleColumn/XElementOrNullListMaterializer`2.cs @@ -2,103 +2,102 @@ using System.Xml.Linq; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a list of strings. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class XElementOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand + where TParameter : DbParameter { + readonly ListOptions m_ListOptions; + /// - /// Materializes the result set as a list of strings. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class XElementOrNullListMaterializer : SingleColumnMaterializer> where TCommand : DbCommand - where TParameter : DbParameter + /// The command builder. + /// Name of the desired column. + /// The list options. + public XElementOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) + : base(commandBuilder, columnName) { - readonly ListOptions m_ListOptions; + m_ListOptions = listOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// Name of the desired column. - /// The list options. - public XElementOrNullListMaterializer(DbCommandBuilder commandBuilder, string? columnName = null, ListOptions listOptions = ListOptions.None) - : base(commandBuilder, columnName) - { - m_ListOptions = listOptions; - } + /// + /// Execute the operation synchronously. + /// + /// + public override List Execute(object? state = null) + { + var result = new List(); - /// - /// Execute the operation synchronously. - /// - /// - public override List Execute(object? state = null) + Prepare().Execute(cmd => { - var result = new List(); - - Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (reader.Read()) + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var rowCount = 0; + while (reader.Read()) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(XElement.Parse(reader.GetString(i))); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(XElement.Parse(reader.GetString(i))); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, state); + return rowCount; + } + }, state); - return result; - } + return result; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - var result = new List(); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task> ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var result = new List(); - await Prepare().ExecuteAsync(async cmd => + await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) - throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); + if (reader.FieldCount > 1 && !m_ListOptions.HasFlag(ListOptions.IgnoreExtraColumns)) + throw new UnexpectedDataException($"Expected one column but found {reader.FieldCount} columns"); - var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; - var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); + var columnCount = m_ListOptions.HasFlag(ListOptions.FlattenExtraColumns) ? reader.FieldCount : 1; + var discardNulls = m_ListOptions.HasFlag(ListOptions.DiscardNulls); - var rowCount = 0; - while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + var rowCount = 0; + while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + rowCount++; + for (var i = 0; i < columnCount; i++) { - rowCount++; - for (var i = 0; i < columnCount; i++) - { - if (!reader.IsDBNull(i)) - result.Add(XElement.Parse(reader.GetString(i))); - else if (!discardNulls) - result.Add(null); - } + if (!reader.IsDBNull(i)) + result.Add(XElement.Parse(reader.GetString(i))); + else if (!discardNulls) + result.Add(null); } - return rowCount; } - }, cancellationToken, state).ConfigureAwait(false); + return rowCount; + } + }, cancellationToken, state).ConfigureAwait(false); - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowMaterializer`2.cs index d6e8acc84..8adc9e039 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowMaterializer`2.cs @@ -2,97 +2,96 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a single row. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DataRowMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { + readonly RowOptions m_RowOptions; + + /// Initializes a new instance of the class. + /// The command builder. + /// The row options. + public DataRowMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) + { + m_RowOptions = rowOptions; + } + + public override IReadOnlyList DesiredColumns() => AllColumns; + /// - /// Materializes the result set as a single row. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DataRowMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + public override DataRow Execute(object? state = null) { - readonly RowOptions m_RowOptions; - - /// Initializes a new instance of the class. - /// The command builder. - /// The row options. - public DataRowMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; - } + var executionToken = Prepare(); - public override IReadOnlyList DesiredColumns() => AllColumns; + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + var table = new DataTable(); + ds.Tables.Add(table); - /// - /// Execute the operation synchronously. - /// - /// - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - public override DataRow Execute(object? state = null) + executionToken.Execute(cmd => { - var executionToken = Prepare(); - - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - var table = new DataTable(); - ds.Tables.Add(table); - - executionToken.Execute(cmd => - { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - table.Load(reader); - return table.Rows.Count; - } - }, state); - - if (table.Rows.Count == 0) - { - throw new MissingDataException("No rows were returned"); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToDataRowOrNull` instead of `.ToDataRow`."); + table.Load(reader); + return table.Rows.Count; } - return table.Rows[0]; - } + }, state); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "")] - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + if (table.Rows.Count == 0) { - var executionToken = Prepare(); + throw new MissingDataException("No rows were returned"); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToDataRowOrNull` instead of `.ToDataRow`."); + } + return table.Rows[0]; + } - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - var table = new DataTable(); - ds.Tables.Add(table); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "")] + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => - { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - table.Load(reader); - return table.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + var table = new DataTable(); + ds.Tables.Add(table); - if (table.Rows.Count == 0) - { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToDataRowOrNull` instead of `.ToDataRow`."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table.Load(reader); + return table.Rows.Count; } - return table.Rows[0]; + }, cancellationToken, state).ConfigureAwait(false); + + if (table.Rows.Count == 0) + { + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToDataRowOrNull` instead of `.ToDataRow`."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + return table.Rows[0]; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowOrNullMaterializer`2.cs index d7ce2fdcb..6c3c60635 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DataRowOrNullMaterializer`2.cs @@ -2,103 +2,102 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a single row. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DataRowOrNullMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { + readonly RowOptions m_RowOptions; + + /// Initializes a new instance of the class. + /// The command builder. + /// The row options. + public DataRowOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) + { + m_RowOptions = rowOptions; + } + + public override IReadOnlyList DesiredColumns() => AllColumns; + /// - /// Materializes the result set as a single row. + /// Execute the operation synchronously. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DataRowOrNullMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + /// + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + public override DataRow? Execute(object? state = null) { - readonly RowOptions m_RowOptions; - - /// Initializes a new instance of the class. - /// The command builder. - /// The row options. - public DataRowOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; - } + var executionToken = Prepare(); - public override IReadOnlyList DesiredColumns() => AllColumns; + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + var table = new DataTable(); + ds.Tables.Add(table); - /// - /// Execute the operation synchronously. - /// - /// - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - public override DataRow? Execute(object? state = null) + executionToken.Execute(cmd => { - var executionToken = Prepare(); - - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - var table = new DataTable(); - ds.Tables.Add(table); - - executionToken.Execute(cmd => - { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - table.Load(reader); - return table.Rows.Count; - } - }, state); - - if (table.Rows.Count == 0) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table.Load(reader); + return table.Rows.Count; } - return table.Rows[0]; - } + }, state); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "")] - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + if (table.Rows.Count == 0) { - var executionToken = Prepare(); + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + } + return table.Rows[0]; + } - var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; - var table = new DataTable(); - ds.Tables.Add(table); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "")] + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var executionToken = Prepare(); - await executionToken.ExecuteAsync(async cmd => - { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - table.Load(reader); - return table.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + var ds = new DataSet() { EnforceConstraints = false /*needed for PostgreSql*/}; + var table = new DataTable(); + ds.Tables.Add(table); - if (table.Rows.Count == 0) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table.Load(reader); + return table.Rows.Count; } - return table.Rows[0]; + }, cancellationToken, state).ConfigureAwait(false); + + if (table.Rows.Count == 0) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + return table.Rows[0]; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectMaterializer`2.cs index 67cf27e00..5a1b02e76 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectMaterializer`2.cs @@ -2,110 +2,109 @@ using System.Dynamic; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a dynamic object. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DynamicObjectMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { + readonly RowOptions m_RowOptions; + /// - /// Materializes the result set as a dynamic object. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DynamicObjectMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + /// The associated operation. + /// The row options. + public DynamicObjectMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) { - readonly RowOptions m_RowOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - /// The row options. - public DynamicObjectMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; - } + m_RowOptions = rowOptions; + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// The state. - /// System.Nullable<dynamic>. - /// No rows were returned - /// Expected 1 row but received " + rowCount + " rows - public override dynamic Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// The state. + /// System.Nullable<dynamic>. + /// No rows were returned + /// Expected 1 row but received " + rowCount + " rows + public override dynamic Execute(object? state = null) + { + ExpandoObject? row = null; + var rowCount = Prepare().Execute(cmd => { - ExpandoObject? row = null; - var rowCount = Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.Read()) { - if (reader.Read()) - { - row = new ExpandoObject(); - reader.PopulateDictionary(row); - } - return (row != null ? 1 : 0) + reader.RemainingRowCount(); + row = new ExpandoObject(); + reader.PopulateDictionary(row); } - }, state); - - if (rowCount == 0 || row == null) - { - throw new MissingDataException("No rows were returned. It was this expected, use `.ToDynamicObjectOrNull` instead of `.ToDynamicObject`."); - } - else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + return (row != null ? 1 : 0) + reader.RemainingRowCount(); } + }, state); - return row; + if (rowCount == 0 || row == null) + { + throw new MissingDataException("No rows were returned. It was this expected, use `.ToDynamicObjectOrNull` instead of `.ToDynamicObject`."); } - - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task<System.Nullable<dynamic>>. - /// No rows were returned - /// Expected 1 row but received " + rowCount + " rows - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) { - ExpandoObject? row = null; + throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + } + + return row; + } + + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task<System.Nullable<dynamic>>. + /// No rows were returned + /// Expected 1 row but received " + rowCount + " rows + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + ExpandoObject? row = null; - var rowCount = await Prepare().ExecuteAsync(async cmd => + var rowCount = await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { - if (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) - { - row = new ExpandoObject(); - reader.PopulateDictionary(row); - } - return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); + row = new ExpandoObject(); + reader.PopulateDictionary(row); } - }, cancellationToken, state).ConfigureAwait(false); - - if (rowCount == 0 || row == null) - { - throw new MissingDataException("No rows were returned. It was this expected, use `.ToDynamicObjectOrNull` instead of `.ToDynamicObject`."); - } - else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); } + }, cancellationToken, state).ConfigureAwait(false); - return row; + if (rowCount == 0 || row == null) + { + throw new MissingDataException("No rows were returned. It was this expected, use `.ToDynamicObjectOrNull` instead of `.ToDynamicObject`."); + } + else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + + return row; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectOrNullMaterializer`2.cs index a6e0a0084..3ec877140 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/DynamicObjectOrNullMaterializer`2.cs @@ -2,116 +2,115 @@ using System.Dynamic; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a dynamic object. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class DynamicObjectOrNullMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { + readonly RowOptions m_RowOptions; + /// - /// Materializes the result set as a dynamic object. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class DynamicObjectOrNullMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + /// The associated operation. + /// The row options. + public DynamicObjectOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) { - readonly RowOptions m_RowOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The associated operation. - /// The row options. - public DynamicObjectOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; - } + m_RowOptions = rowOptions; + } - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Execute the operation synchronously. - /// - /// The state. - /// System.Nullable<dynamic>. - /// No rows were returned - /// Expected 1 row but received " + rowCount + " rows - public override dynamic? Execute(object? state = null) + /// + /// Execute the operation synchronously. + /// + /// The state. + /// System.Nullable<dynamic>. + /// No rows were returned + /// Expected 1 row but received " + rowCount + " rows + public override dynamic? Execute(object? state = null) + { + ExpandoObject? row = null; + var rowCount = Prepare().Execute(cmd => { - ExpandoObject? row = null; - var rowCount = Prepare().Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) + if (reader.Read()) { - if (reader.Read()) - { - row = new ExpandoObject(); - reader.PopulateDictionary(row); - } - return (row != null ? 1 : 0) + reader.RemainingRowCount(); + row = new ExpandoObject(); + reader.PopulateDictionary(row); } - }, state); - - if (rowCount == 0 || row == null) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + return (row != null ? 1 : 0) + reader.RemainingRowCount(); } + }, state); - return row; + if (rowCount == 0 || row == null) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); } - - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task<System.Nullable<dynamic>>. - /// No rows were returned - /// Expected 1 row but received " + rowCount + " rows - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) { - ExpandoObject? row = null; + throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + } + + return row; + } + + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task<System.Nullable<dynamic>>. + /// No rows were returned + /// Expected 1 row but received " + rowCount + " rows + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + ExpandoObject? row = null; - var rowCount = await Prepare().ExecuteAsync(async cmd => + var rowCount = await Prepare().ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) + if (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { - if (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) - { - row = new ExpandoObject(); - reader.PopulateDictionary(row); - } - return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); + row = new ExpandoObject(); + reader.PopulateDictionary(row); } - }, cancellationToken, state).ConfigureAwait(false); - - if (rowCount == 0 || row == null) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); } + }, cancellationToken, state).ConfigureAwait(false); - return row; + if (rowCount == 0 || row == null) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); + } + else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + rowCount + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + + return row; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectMaterializer`3.cs index e1d34d924..d823f9237 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectMaterializer`3.cs @@ -1,99 +1,97 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an instance of the indicated type. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the object returned. +/// +internal sealed class ObjectMaterializer : ConstructibleMaterializer + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class { + readonly RowOptions m_RowOptions; + /// - /// Materializes the result set as an instance of the indicated type. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the object returned. - /// - internal sealed class ObjectMaterializer : ConstructibleMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class + /// The command builder. + /// The row options. + /// + /// Type {typeof(TObject).Name} has does not have any non-default constructors. or Type + /// {typeof(TObject).Name} has more than one non-default constructor. Please use the + /// WithConstructor method to specify which one to use. + /// + public ObjectMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) { - readonly RowOptions m_RowOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The row options. - /// - /// Type {typeof(TObject).Name} has does not have any non-default constructors. or Type - /// {typeof(TObject).Name} has more than one non-default constructor. Please use the - /// WithConstructor method to specify which one to use. - /// - public ObjectMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; + m_RowOptions = rowOptions; - if (m_RowOptions.HasFlag(RowOptions.InferConstructor)) - Constructor = InferConstructor(); + if (m_RowOptions.HasFlag(RowOptions.InferConstructor)) + Constructor = InferConstructor(); + } - } + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// System.Nullable<TObject>. + public override TObject Execute(object? state = null) + { + IReadOnlyDictionary? row = null; - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// System.Nullable<TObject>. - public override TObject Execute(object? state = null) + var executionToken = Prepare(); + var rowCount = executionToken.Execute(cmd => { - IReadOnlyDictionary? row = null; - - var executionToken = Prepare(); - var rowCount = executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - row = reader.ReadDictionary(); - return (row != null ? 1 : 0) + reader.RemainingRowCount(); - } - }, state); + row = reader.ReadDictionary(); + return (row != null ? 1 : 0) + reader.RemainingRowCount(); + } + }, state); - return ConstructObject(row, rowCount); - } + return ConstructObject(row, rowCount); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - IReadOnlyDictionary? row = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + IReadOnlyDictionary? row = null; - var executionToken = Prepare(); - var rowCount = await executionToken.ExecuteAsync(async cmd => + var executionToken = Prepare(); + var rowCount = await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - row = await reader.ReadDictionaryAsync().ConfigureAwait(false); - return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); - } - }, cancellationToken, state).ConfigureAwait(false); + row = await reader.ReadDictionaryAsync().ConfigureAwait(false); + return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); + } + }, cancellationToken, state).ConfigureAwait(false); - return ConstructObject(row, rowCount); - } + return ConstructObject(row, rowCount); + } - TObject ConstructObject(IReadOnlyDictionary? row, int? rowCount) + TObject ConstructObject(IReadOnlyDictionary? row, int? rowCount) + { + if (rowCount == 0 || row == null) { - if (rowCount == 0 || row == null) - { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToObjectOrNull` instead of `.ToObject`."); - } - else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException($"Expected 1 row but received {rowCount} rows. If this was expected, use `RowOptions.DiscardExtraRows`."); - } - return MaterializerUtilities.ConstructObject(row, Constructor); + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToObjectOrNull` instead of `.ToObject`."); + } + else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException($"Expected 1 row but received {rowCount} rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + return MaterializerUtilities.ConstructObject(row, Constructor, Converter); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectOrNullMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectOrNullMaterializer`3.cs index 8e6011019..8a556a3d4 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectOrNullMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/ObjectOrNullMaterializer`3.cs @@ -1,108 +1,107 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as an instance of the indicated type. +/// +/// The type of the t command type. +/// The type of the t parameter type. +/// The type of the object returned. +/// +internal sealed class ObjectOrNullMaterializer : ConstructibleMaterializer + where TCommand : DbCommand + where TParameter : DbParameter + where TObject : class { + readonly RowOptions m_RowOptions; + /// - /// Materializes the result set as an instance of the indicated type. + /// Initializes a new instance of the class. /// - /// The type of the t command type. - /// The type of the t parameter type. - /// The type of the object returned. - /// - internal sealed class ObjectOrNullMaterializer : ConstructibleMaterializer - where TCommand : DbCommand - where TParameter : DbParameter - where TObject : class + /// The command builder. + /// The row options. + /// + /// Type {typeof(TObject).Name} has does not have any non-default constructors. or Type + /// {typeof(TObject).Name} has more than one non-default constructor. Please use the + /// WithConstructor method to specify which one to use. + /// + public ObjectOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) { - readonly RowOptions m_RowOptions; + m_RowOptions = rowOptions; - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - /// The row options. - /// - /// Type {typeof(TObject).Name} has does not have any non-default constructors. or Type - /// {typeof(TObject).Name} has more than one non-default constructor. Please use the - /// WithConstructor method to specify which one to use. - /// - public ObjectOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) + if (m_RowOptions.HasFlag(RowOptions.InferConstructor)) { - m_RowOptions = rowOptions; - - if (m_RowOptions.HasFlag(RowOptions.InferConstructor)) - { - var constructors = ObjectMetadata.Constructors.Where(x => x.Signature.Length > 0).ToList(); - if (constructors.Count == 0) - throw new MappingException($"Type {typeof(TObject).Name} has does not have any non-default constructors."); - if (constructors.Count > 1) - throw new MappingException($"Type {typeof(TObject).Name} has more than one non-default constructor. Please use the WithConstructor method to specify which one to use."); - Constructor = constructors[0]; - } + var constructors = ObjectMetadata.Constructors.Where(x => x.Signature.Length > 0).ToList(); + if (constructors.Count == 0) + throw new MappingException($"Type {typeof(TObject).Name} has does not have any non-default constructors."); + if (constructors.Count > 1) + throw new MappingException($"Type {typeof(TObject).Name} has more than one non-default constructor. Please use the WithConstructor method to specify which one to use."); + Constructor = constructors[0]; } + } - /// - /// Execute the operation synchronously. - /// - /// User defined state, usually used for logging. - /// System.Nullable<TObject>. - public override TObject? Execute(object? state = null) - { - IReadOnlyDictionary? row = null; + /// + /// Execute the operation synchronously. + /// + /// User defined state, usually used for logging. + /// System.Nullable<TObject>. + public override TObject? Execute(object? state = null) + { + IReadOnlyDictionary? row = null; - var executionToken = Prepare(); - var rowCount = executionToken.Execute(cmd => + var executionToken = Prepare(); + var rowCount = executionToken.Execute(cmd => + { + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - row = reader.ReadDictionary(); - return (row != null ? 1 : 0) + reader.RemainingRowCount(); - } - }, state); + row = reader.ReadDictionary(); + return (row != null ? 1 : 0) + reader.RemainingRowCount(); + } + }, state); - return ConstructObject(row, rowCount); - } + return ConstructObject(row, rowCount); + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - IReadOnlyDictionary? row = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + IReadOnlyDictionary? row = null; - var executionToken = Prepare(); - var rowCount = await executionToken.ExecuteAsync(async cmd => + var executionToken = Prepare(); + var rowCount = await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - row = await reader.ReadDictionaryAsync().ConfigureAwait(false); - return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); - } - }, cancellationToken, state).ConfigureAwait(false); + row = await reader.ReadDictionaryAsync().ConfigureAwait(false); + return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); + } + }, cancellationToken, state).ConfigureAwait(false); - return ConstructObject(row, rowCount); - } + return ConstructObject(row, rowCount); + } - TObject? ConstructObject(IReadOnlyDictionary? row, int? rowCount) + TObject? ConstructObject(IReadOnlyDictionary? row, int? rowCount) + { + if (rowCount == 0 || row == null) { - if (rowCount == 0 || row == null) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) - { - throw new UnexpectedDataException($"Expected 1 row but received {rowCount} rows. If this was expected, use `RowOptions.DiscardExtraRows`."); - } - return MaterializerUtilities.ConstructObject(row, Constructor); + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); + } + else if (rowCount > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException($"Expected 1 row but received {rowCount} rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + return MaterializerUtilities.ConstructObject(row, Constructor, Converter); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RefreshMaterializer`3.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RefreshMaterializer`3.cs index 4d193ba8a..4f8689635 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RefreshMaterializer`3.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RefreshMaterializer`3.cs @@ -2,91 +2,90 @@ using Tortuga.Anchor.Metadata; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal class RefreshMaterializer : Materializer + where TCommand : DbCommand + where TParameter : DbParameter + where TArgument : class { - internal class RefreshMaterializer : Materializer - where TCommand : DbCommand - where TParameter : DbParameter - where TArgument : class + readonly ObjectDbCommandBuilder m_CommandBuilder; + readonly ClassMetadata m_ObjectMetadata; + + /// + /// Initializes a new instance of the class. + /// + /// The command builder. + public RefreshMaterializer(ObjectDbCommandBuilder commandBuilder) + : base(commandBuilder) { - readonly ObjectDbCommandBuilder m_CommandBuilder; - readonly ClassMetadata m_ObjectMetadata; + m_ObjectMetadata = MetadataCache.GetMetadata(typeof(TArgument)); + m_CommandBuilder = commandBuilder; + } - /// - /// Initializes a new instance of the class. - /// - /// The command builder. - public RefreshMaterializer(ObjectDbCommandBuilder commandBuilder) - : base(commandBuilder) - { - m_ObjectMetadata = MetadataCache.GetMetadata(typeof(TArgument)); - m_CommandBuilder = commandBuilder; - } + /// + /// Returns the list of columns the result materializer would like to have. + /// + /// + public override IReadOnlyList DesiredColumns() => m_ObjectMetadata.ColumnsFor; - /// - /// Returns the list of columns the result materializer would like to have. - /// - /// - public override IReadOnlyList DesiredColumns() => m_ObjectMetadata.ColumnsFor; + /// + /// Execute the operation synchronously. + /// + /// + public override TArgument? Execute(object? state = null) + { + IReadOnlyDictionary? row = null; - /// - /// Execute the operation synchronously. - /// - /// - public override TArgument? Execute(object? state = null) + var executionToken = Prepare(); + var rowCount = executionToken.Execute(cmd => { - IReadOnlyDictionary? row = null; - - var executionToken = Prepare(); - var rowCount = executionToken.Execute(cmd => + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - row = reader.ReadDictionary(); - return (row != null ? 1 : 0) + reader.RemainingRowCount(); - } - }, state); + row = reader.ReadDictionary(); + return (row != null ? 1 : 0) + reader.RemainingRowCount(); + } + }, state); - if (rowCount == 0 || row == null) - throw new DataException("No rows were returned"); - else if (rowCount > 1) - throw new DataException($"Expected 1 row but received {rowCount} rows."); + if (rowCount == 0 || row == null) + throw new DataException("No rows were returned"); + else if (rowCount > 1) + throw new DataException($"Expected 1 row but received {rowCount} rows."); - //update the ArgumentValue with any new keys, calculated fields, etc. - MaterializerUtilities.PopulateComplexObject(row, m_CommandBuilder.ArgumentValue, null); + //update the ArgumentValue with any new keys, calculated fields, etc. + MaterializerUtilities.PopulateComplexObject(row, m_CommandBuilder.ArgumentValue, null, Converter); - return m_CommandBuilder.ArgumentValue; - } + return m_CommandBuilder.ArgumentValue; + } - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) - { - IReadOnlyDictionary? row = null; + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + IReadOnlyDictionary? row = null; - var executionToken = Prepare(); - var rowCount = await executionToken.ExecuteAsync(async cmd => + var executionToken = Prepare(); + var rowCount = await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - row = await reader.ReadDictionaryAsync().ConfigureAwait(false); - return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); - } - }, cancellationToken, state).ConfigureAwait(false); + row = await reader.ReadDictionaryAsync().ConfigureAwait(false); + return (row != null ? 1 : 0) + await reader.RemainingRowCountAsync().ConfigureAwait(false); + } + }, cancellationToken, state).ConfigureAwait(false); - if (rowCount == 0 || row == null) - throw new DataException("No rows were returned"); - else if (rowCount > 1) - throw new DataException($"Expected 1 row but received {rowCount} rows."); + if (rowCount == 0 || row == null) + throw new DataException("No rows were returned"); + else if (rowCount > 1) + throw new DataException($"Expected 1 row but received {rowCount} rows."); - //update the ArgumentValue with any new keys, calculated fields, etc. - MaterializerUtilities.PopulateComplexObject(row, m_CommandBuilder.ArgumentValue, null); + //update the ArgumentValue with any new keys, calculated fields, etc. + MaterializerUtilities.PopulateComplexObject(row, m_CommandBuilder.ArgumentValue, null, Converter); - return m_CommandBuilder.ArgumentValue; - } + return m_CommandBuilder.ArgumentValue; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowMaterializer`2.cs index 9fa8b17e1..ff3bbb1ce 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowMaterializer`2.cs @@ -1,93 +1,92 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a single row. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class RowMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// Materializes the result set as a single row. - /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class RowMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + readonly RowOptions m_RowOptions; + + public RowMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) { - readonly RowOptions m_RowOptions; + m_RowOptions = rowOptions; + } - public RowMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; - } + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Execute the operation synchronously. + /// + /// + public override Row Execute(object? state = null) + { + var executionToken = Prepare(); - /// - /// Execute the operation synchronously. - /// - /// - public override Row Execute(object? state = null) + Table? table = null; + executionToken.Execute(cmd => { - var executionToken = Prepare(); - - Table? table = null; - executionToken.Execute(cmd => - { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, state); - - if (table!.Rows.Count == 0) - { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToRowOrNull` instead of `.ToRow`."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table = new Table(reader, Converter); + return table.Rows.Count; } - return table.Rows[0]; - } + }, state); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + if (table!.Rows.Count == 0) + { + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToRowOrNull` instead of `.ToRow`."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) { - var executionToken = Prepare(); + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + } + return table.Rows[0]; + } - Table? table = null; - await executionToken.ExecuteAsync(async cmd => - { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var executionToken = Prepare(); - if (table!.Rows.Count == 0) - { - throw new MissingDataException($"No rows were returned. It was this expected, use `.ToRowOrNull` instead of `.ToRow`."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + Table? table = null; + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table = new Table(reader, Converter); + return table.Rows.Count; } - return table.Rows[0]; + }, cancellationToken, state).ConfigureAwait(false); + + if (table!.Rows.Count == 0) + { + throw new MissingDataException($"No rows were returned. It was this expected, use `.ToRowOrNull` instead of `.ToRow`."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + return table.Rows[0]; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowOrNullMaterializer`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowOrNullMaterializer`2.cs index 7f0dc63dc..9fff40c0a 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowOrNullMaterializer`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/SingleRow/RowOrNullMaterializer`2.cs @@ -1,99 +1,98 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +/// +/// Materializes the result set as a single row. +/// +/// The type of the t command type. +/// The type of the t parameter type. +internal sealed class RowOrNullMaterializer : Materializer where TCommand : DbCommand + where TParameter : DbParameter { - /// - /// Materializes the result set as a single row. - /// - /// The type of the t command type. - /// The type of the t parameter type. - internal sealed class RowOrNullMaterializer : Materializer where TCommand : DbCommand - where TParameter : DbParameter + readonly RowOptions m_RowOptions; + + public RowOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) + : base(commandBuilder) { - readonly RowOptions m_RowOptions; + m_RowOptions = rowOptions; + } - public RowOrNullMaterializer(DbCommandBuilder commandBuilder, RowOptions rowOptions) - : base(commandBuilder) - { - m_RowOptions = rowOptions; - } + /// + /// Returns the list of columns the materializer would like to have. + /// + /// + /// IReadOnlyList<System.String>. + /// + /// + /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. + /// + public override IReadOnlyList DesiredColumns() => AllColumns; - /// - /// Returns the list of columns the materializer would like to have. - /// - /// - /// IReadOnlyList<System.String>. - /// - /// - /// If AutoSelectDesiredColumns is returned, the command builder is allowed to choose which columns to return. If NoColumns is returned, the command builder should omit the SELECT/OUTPUT clause. - /// - public override IReadOnlyList DesiredColumns() => AllColumns; + /// + /// Execute the operation synchronously. + /// + /// + public override Row? Execute(object? state = null) + { + var executionToken = Prepare(); - /// - /// Execute the operation synchronously. - /// - /// - public override Row? Execute(object? state = null) + Table? table = null; + executionToken.Execute(cmd => { - var executionToken = Prepare(); - - Table? table = null; - executionToken.Execute(cmd => - { - using (var reader = cmd.ExecuteReader(CommandBehavior)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, state); - - if (table!.Rows.Count == 0) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + using (var reader = cmd.ExecuteReader(CommandBehavior)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table = new Table(reader, Converter); + return table.Rows.Count; } - return table.Rows[0]; - } + }, state); - /// - /// Execute the operation asynchronously. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// - public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + if (table!.Rows.Count == 0) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) { - var executionToken = Prepare(); + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + } + return table.Rows[0]; + } - Table? table = null; - await executionToken.ExecuteAsync(async cmd => - { - using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) - { - table = new Table(reader); - return table.Rows.Count; - } - }, cancellationToken, state).ConfigureAwait(false); + /// + /// Execute the operation asynchronously. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// + public override async Task ExecuteAsync(CancellationToken cancellationToken, object? state = null) + { + var executionToken = Prepare(); - if (table!.Rows.Count == 0) - { - if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) - return null; - else - throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); - } - else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + Table? table = null; + await executionToken.ExecuteAsync(async cmd => + { + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior, cancellationToken).ConfigureAwait(false)) { - throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); + table = new Table(reader, Converter); + return table.Rows.Count; } - return table.Rows[0]; + }, cancellationToken, state).ConfigureAwait(false); + + if (table!.Rows.Count == 0) + { + if (!m_RowOptions.HasFlag(RowOptions.PreventEmptyResults)) + return null; + else + throw new MissingDataException($"No rows were returned and {nameof(RowOptions)}.{nameof(RowOptions.PreventEmptyResults)} was enabled."); + } + else if (table.Rows.Count > 1 && !m_RowOptions.HasFlag(RowOptions.DiscardExtraRows)) + { + throw new UnexpectedDataException("Expected 1 row but received " + table.Rows.Count + " rows. If this was expected, use `RowOptions.DiscardExtraRows`."); } + return table.Rows[0]; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/StreamingObjectConstructor.cs b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/StreamingObjectConstructor.cs index 3dd100fc1..b78297ed6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Materializers/StreamingObjectConstructor.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Materializers/StreamingObjectConstructor.cs @@ -8,317 +8,319 @@ using Tortuga.Chain.Metadata; using static Tortuga.Chain.Materializers.MaterializerUtilities; -namespace Tortuga.Chain.Materializers +namespace Tortuga.Chain.Materializers; + +internal sealed class StreamingObjectConstructor : IDisposable + where T : class { - internal sealed class StreamingObjectConstructor : IDisposable - where T : class - { - static readonly ImmutableArray> s_AllMappedProperties; - static readonly ImmutableArray> s_DecomposedProperties; + static readonly ImmutableArray> s_AllMappedProperties; + static readonly ImmutableArray> s_DecomposedProperties; - static readonly Type[] s_DefaultConstructor = Array.Empty(); + static readonly Type[] s_DefaultConstructor = Array.Empty(); - readonly ConstructorMetadata m_Constructor; + readonly ConstructorMetadata m_Constructor; - readonly StreamingObjectConstructorDictionary m_Dictionary; + readonly MaterializerTypeConverter m_Converter; + readonly StreamingObjectConstructorDictionary m_Dictionary; - readonly List>? m_MappedProperties; - readonly Dictionary m_NullableColumns; - readonly Dictionary m_Ordinals; - DbDataReader? m_Source; + readonly List>? m_MappedProperties; + readonly Dictionary m_NullableColumns; + readonly Dictionary m_Ordinals; + DbDataReader? m_Source; - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static StreamingObjectConstructor() - { - var methodType = typeof(StreamingObjectConstructor).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Single(m => m.Name == "CreateMappedProperty_Helper"); + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + static StreamingObjectConstructor() + { + var methodType = typeof(StreamingObjectConstructor).GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Single(m => m.Name == "CreateMappedProperty_Helper"); - var mappedProperties = new List>(); - var decomposedProperties = new List>(); + var mappedProperties = new List>(); + var decomposedProperties = new List>(); - foreach (var property in MetadataCache.GetMetadata(typeof(T)).Properties) + foreach (var property in MetadataCache.GetMetadata(typeof(T)).Properties) + { + if (property.MappedColumnName != null) { - if (property.MappedColumnName != null) + if (property.CanWrite) { - if (property.CanWrite) - { - var genericMethod = methodType.MakeGenericMethod(property.PropertyType); - var mapper = (MappedProperty)genericMethod.Invoke(null, new object?[] { property.MappedColumnName, property })!; - - mappedProperties.Add(mapper); - } - - if (property.Decompose) - { - decomposedProperties.Add(new MappedProperty(property.MappedColumnName, property)); - } + var genericMethod = methodType.MakeGenericMethod(property.PropertyType); + var mapper = (MappedProperty)genericMethod.Invoke(null, new object?[] { property.MappedColumnName, property })!; + + mappedProperties.Add(mapper); } - } - s_AllMappedProperties = mappedProperties.ToImmutableArray(); - s_DecomposedProperties = decomposedProperties.ToImmutableArray(); + if (property.Decompose) + { + decomposedProperties.Add(new MappedProperty(property.MappedColumnName, property)); + } + } } - public StreamingObjectConstructor(DbDataReader source, ConstructorMetadata? constructor, IReadOnlyList nonNullableColumns) + s_AllMappedProperties = mappedProperties.ToImmutableArray(); + s_DecomposedProperties = decomposedProperties.ToImmutableArray(); + } + + public StreamingObjectConstructor(DbDataReader source, ConstructorMetadata? constructor, IReadOnlyList nonNullableColumns, MaterializerTypeConverter converter) + { + m_Converter = converter ?? new(); + m_Source = source; + m_Ordinals = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); + m_NullableColumns = new Dictionary(source.FieldCount); + for (var i = 0; i < source.FieldCount; i++) { - m_Source = source; - m_Ordinals = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); - m_NullableColumns = new Dictionary(source.FieldCount); - for (var i = 0; i < source.FieldCount; i++) - { - var columnName = source.GetName(i); - m_Ordinals.Add(columnName, i); - m_NullableColumns.Add(i, !nonNullableColumns.Any(c => c.SqlName == columnName)); //assume nullable unless proven otherwise - } + var columnName = source.GetName(i); + m_Ordinals.Add(columnName, i); + m_NullableColumns.Add(i, !nonNullableColumns.Any(c => c.SqlName == columnName)); //assume nullable unless proven otherwise + } - if (constructor == null) - constructor = MetadataCache.GetMetadata(typeof(T)).Constructors.Find(s_DefaultConstructor); - if (constructor == null) - throw new MappingException($"Cannot find a default constructor for {typeof(T).Name}"); + if (constructor == null) + constructor = MetadataCache.GetMetadata(typeof(T)).Constructors.Find(s_DefaultConstructor); + if (constructor == null) + throw new MappingException($"Cannot find a default constructor for {typeof(T).Name}"); - var desiredType = typeof(T); + var desiredType = typeof(T); - m_Constructor = constructor; + m_Constructor = constructor; - var constructorParameters = m_Constructor.ParameterNames; - for (var i = 0; i < constructorParameters.Length; i++) - { - if (!m_Ordinals.ContainsKey(constructorParameters[i])) - throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); - } + var constructorParameters = m_Constructor.ParameterNames; + for (var i = 0; i < constructorParameters.Length; i++) + { + if (!m_Ordinals.ContainsKey(constructorParameters[i])) + throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); + } - m_Dictionary = new StreamingObjectConstructorDictionary(this); + m_Dictionary = new StreamingObjectConstructorDictionary(this); - if (constructor.Signature.Length == 0) - { - m_MappedProperties = new List>(); + if (constructor.Signature.Length == 0) + { + m_MappedProperties = new List>(); - foreach (var mapper in s_AllMappedProperties) - { - if (m_Dictionary.ContainsKey(mapper.MappedColumnName)) - m_MappedProperties.Add(new OrdinalMappedProperty(mapper, m_Ordinals[mapper.MappedColumnName])); - } + foreach (var mapper in s_AllMappedProperties) + { + if (m_Dictionary.ContainsKey(mapper.MappedColumnName)) + m_MappedProperties.Add(new OrdinalMappedProperty(mapper, m_Ordinals[mapper.MappedColumnName])); } } + } - public StreamingObjectConstructor(DbDataReader source, IReadOnlyList? constructorSignature, IReadOnlyList nonNullableColumns) + public StreamingObjectConstructor(DbDataReader source, IReadOnlyList? constructorSignature, IReadOnlyList nonNullableColumns, MaterializerTypeConverter converter) + { + m_Converter = converter ?? new(); + m_Source = source; + m_Ordinals = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); + m_NullableColumns = new Dictionary(source.FieldCount); + for (var i = 0; i < source.FieldCount; i++) { - m_Source = source; - m_Ordinals = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); - m_NullableColumns = new Dictionary(source.FieldCount); - for (var i = 0; i < source.FieldCount; i++) - { - var columnName = source.GetName(i); - m_Ordinals.Add(columnName, i); - m_NullableColumns.Add(i, !nonNullableColumns.Any(c => c.SqlName == columnName)); //assume nullable unless proven otherwise - } - constructorSignature ??= s_DefaultConstructor; + var columnName = source.GetName(i); + m_Ordinals.Add(columnName, i); + m_NullableColumns.Add(i, !nonNullableColumns.Any(c => c.SqlName == columnName)); //assume nullable unless proven otherwise + } + constructorSignature ??= s_DefaultConstructor; - var desiredType = typeof(T); - var constructor = MetadataCache.GetMetadata(desiredType).Constructors.Find(constructorSignature); + var desiredType = typeof(T); + var constructor = MetadataCache.GetMetadata(desiredType).Constructors.Find(constructorSignature); - if (constructor == null) - { - var types = string.Join(", ", constructorSignature.Select(t => t.Name)); - throw new MappingException($"Cannot find a constructor on {desiredType.Name} with the types [{types}]"); - } - m_Constructor = constructor; + if (constructor == null) + { + var types = string.Join(", ", constructorSignature.Select(t => t.Name)); + throw new MappingException($"Cannot find a constructor on {desiredType.Name} with the types [{types}]"); + } + m_Constructor = constructor; - var constructorParameters = m_Constructor.ParameterNames; - for (var i = 0; i < constructorParameters.Length; i++) - { - if (!m_Ordinals.ContainsKey(constructorParameters[i])) - throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); - } + var constructorParameters = m_Constructor.ParameterNames; + for (var i = 0; i < constructorParameters.Length; i++) + { + if (!m_Ordinals.ContainsKey(constructorParameters[i])) + throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); + } - m_Dictionary = new StreamingObjectConstructorDictionary(this); + m_Dictionary = new StreamingObjectConstructorDictionary(this); - if (constructorSignature.Count == 0) - { - m_MappedProperties = new List>(); + if (constructorSignature.Count == 0) + { + m_MappedProperties = new List>(); - foreach (var mapper in s_AllMappedProperties) - { - if (m_Dictionary.ContainsKey(mapper.MappedColumnName)) - m_MappedProperties.Add(new OrdinalMappedProperty(mapper, m_Ordinals[mapper.MappedColumnName])); - } + foreach (var mapper in s_AllMappedProperties) + { + if (m_Dictionary.ContainsKey(mapper.MappedColumnName)) + m_MappedProperties.Add(new OrdinalMappedProperty(mapper, m_Ordinals[mapper.MappedColumnName])); } } + } - public T? Current { get; private set; } - - public IReadOnlyDictionary CurrentDictionary => m_Dictionary; + public T? Current { get; private set; } - public int RowsRead { get; private set; } + public IReadOnlyDictionary CurrentDictionary => m_Dictionary; - private DbDataReader Source - { - get - { - if (m_Source == null) - throw new ObjectDisposedException(nameof(StreamingObjectConstructor)); - - return m_Source; - } - } + public int RowsRead { get; private set; } - public void Dispose() + private DbDataReader Source + { + get { if (m_Source == null) - return; + throw new ObjectDisposedException(nameof(StreamingObjectConstructor)); - m_Source.Dispose(); - m_Source = null; + return m_Source; } + } - public bool Read([NotNullWhen(true)] out T? value) - { - var result = Source.Read(); - if (result) - { - Current = ConstructObject(); - RowsRead += 1; - } - else - Current = null; + public void Dispose() + { + if (m_Source == null) + return; - value = Current; - return result; - } + m_Source.Dispose(); + m_Source = null; + } - public async Task ReadAsync() + public bool Read([NotNullWhen(true)] out T? value) + { + var result = Source.Read(); + if (result) { - var result = await Source.ReadAsync().ConfigureAwait(false); - if (result) - { - Current = ConstructObject(); - RowsRead += 1; - } - else - Current = null; - return result; + Current = ConstructObject(); + RowsRead += 1; } + else + Current = null; - public List ToList() - { - var result = new List(); - while (Read(out var value)) - result.Add(value); - return result; - } + value = Current; + return result; + } - public async Task> ToListAsync() + public async Task ReadAsync() + { + var result = await Source.ReadAsync().ConfigureAwait(false); + if (result) { - var result = new List(); - while (await ReadAsync().ConfigureAwait(false)) - result.Add(Current!); - return result; + Current = ConstructObject(); + RowsRead += 1; } + else + Current = null; + return result; + } - internal static MappedProperty CreateMappedProperty_Helper(string mappedColumnName, PropertyMetadata propertyMetadata) - { - return new MappedProperty(mappedColumnName, propertyMetadata); - } + public List ToList() + { + var result = new List(); + while (Read(out var value)) + result.Add(value); + return result; + } - internal IEnumerable ToObjects() - { - while (Read(out var value)) - yield return value; - } + public async Task> ToListAsync() + { + var result = new List(); + while (await ReadAsync().ConfigureAwait(false)) + result.Add(Current!); + return result; + } - T ConstructObject() - { - var constructorParameters = m_Constructor.ParameterNames; - var parameters = new object?[constructorParameters.Length]; + internal static MappedProperty CreateMappedProperty_Helper(string mappedColumnName, PropertyMetadata propertyMetadata) + { + return new MappedProperty(mappedColumnName, propertyMetadata); + } + + internal IEnumerable ToObjects() + { + while (Read(out var value)) + yield return value; + } - for (var i = 0; i < constructorParameters.Length; i++) - parameters[i] = m_Dictionary[constructorParameters[i]]; + T ConstructObject() + { + var constructorParameters = m_Constructor.ParameterNames; + var parameters = new object?[constructorParameters.Length]; - var result = (T)m_Constructor.ConstructorInfo.Invoke(parameters); + for (var i = 0; i < constructorParameters.Length; i++) + parameters[i] = m_Dictionary[constructorParameters[i]]; - if (m_MappedProperties != null) - PopulateComplexObject(m_Dictionary, result, null, m_MappedProperties, s_DecomposedProperties); + var result = (T)m_Constructor.ConstructorInfo.Invoke(parameters); - //Change tracking objects shouldn't be materialized as unchanged. - (result as IChangeTracking)?.AcceptChanges(); + if (m_MappedProperties != null) + PopulateComplexObject(m_Dictionary, result, null, m_MappedProperties, s_DecomposedProperties, m_Converter); - return result; - } + //Change tracking objects shouldn't be materialized as unchanged. + (result as IChangeTracking)?.AcceptChanges(); - class StreamingObjectConstructorDictionary : IReadOnlyDictionary, IReadOnlyDictionary - { - readonly StreamingObjectConstructor m_Parent; + return result; + } - public StreamingObjectConstructorDictionary(StreamingObjectConstructor parent) - { - m_Parent = parent; - } + class StreamingObjectConstructorDictionary : IReadOnlyDictionary, IReadOnlyDictionary + { + readonly StreamingObjectConstructor m_Parent; + + public StreamingObjectConstructorDictionary(StreamingObjectConstructor parent) + { + m_Parent = parent; + } - public int Count => m_Parent.Source.FieldCount; + public int Count => m_Parent.Source.FieldCount; - IEnumerable IReadOnlyDictionary.Keys => m_Parent.m_Ordinals.Keys; + IEnumerable IReadOnlyDictionary.Keys => m_Parent.m_Ordinals.Keys; - IEnumerable IReadOnlyDictionary.Keys => m_Parent.m_Ordinals.Values; + IEnumerable IReadOnlyDictionary.Keys => m_Parent.m_Ordinals.Values; - public IEnumerable Values + public IEnumerable Values + { + get { - get - { - var result = new object[m_Parent.Source.FieldCount]; - m_Parent.Source.GetValues(result); - return result; - } + var result = new object[m_Parent.Source.FieldCount]; + m_Parent.Source.GetValues(result); + return result; } + } - public object? this[int key] + public object? this[int key] + { + get { - get - { - var result = m_Parent.Source.GetValue(key); - return result == DBNull.Value ? null : result; - } + var result = m_Parent.Source.GetValue(key); + return result == DBNull.Value ? null : result; } + } - public object? this[string key] => this[m_Parent.m_Ordinals[key]]; + public object? this[string key] => this[m_Parent.m_Ordinals[key]]; - public bool ContainsKey(string key) => m_Parent.m_Ordinals.ContainsKey(key); + public bool ContainsKey(string key) => m_Parent.m_Ordinals.ContainsKey(key); - bool IReadOnlyDictionary.ContainsKey(int key) => key < m_Parent.m_Ordinals.Count; + bool IReadOnlyDictionary.ContainsKey(int key) => key < m_Parent.m_Ordinals.Count; - public IEnumerator> GetEnumerator() - { - for (var i = 0; i < m_Parent.Source.FieldCount; i++) - yield return new KeyValuePair(m_Parent.Source.GetName(i), m_Parent.Source.IsDBNull(i) ? null : m_Parent.Source.GetValue(i)); - } + public IEnumerator> GetEnumerator() + { + for (var i = 0; i < m_Parent.Source.FieldCount; i++) + yield return new KeyValuePair(m_Parent.Source.GetName(i), m_Parent.Source.IsDBNull(i) ? null : m_Parent.Source.GetValue(i)); + } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - IEnumerator> IEnumerable>.GetEnumerator() - { - for (var i = 0; i < m_Parent.Source.FieldCount; i++) - yield return new KeyValuePair(i, m_Parent.Source.IsDBNull(i) ? null : m_Parent.Source.GetValue(i)); - } + IEnumerator> IEnumerable>.GetEnumerator() + { + for (var i = 0; i < m_Parent.Source.FieldCount; i++) + yield return new KeyValuePair(i, m_Parent.Source.IsDBNull(i) ? null : m_Parent.Source.GetValue(i)); + } - bool IReadOnlyDictionary.TryGetValue(string key, out object? value) + bool IReadOnlyDictionary.TryGetValue(string key, out object? value) + { + if (m_Parent.m_Ordinals.ContainsKey(key)) { - if (m_Parent.m_Ordinals.ContainsKey(key)) - { - value = this[key]; - return true; - } - value = null; - return false; + value = this[key]; + return true; } + value = null; + return false; + } - bool IReadOnlyDictionary.TryGetValue(int key, out object? value) + bool IReadOnlyDictionary.TryGetValue(int key, out object? value) + { + if (key < m_Parent.m_Ordinals.Count) { - if (key < m_Parent.m_Ordinals.Count) - { - value = this[key]; - return true; - } - value = null; - return false; + value = this[key]; + return true; } + value = null; + return false; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata.cs index 2eca354b3..4f6dfaeb7 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata.cs @@ -1,199 +1,198 @@ using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Abstract version of ColumnMetadata. +/// +public abstract class ColumnMetadata { /// - /// Abstract version of ColumnMetadata. + /// Initializes a new instance of the class. /// - public abstract class ColumnMetadata + /// The name. + /// if set to true is a computed column. + /// if set to true is a primary key. + /// if set to true [is identity]. + /// Name of the type. + /// Type used by the database. + /// Name of the quoted SQL. + /// Indicates if the column is nullable. + /// The maximum length. + /// The precision. + /// The scale. + /// Full name of the type. + /// The CLR type that matches this column's database type. + protected ColumnMetadata(string name, bool isComputed, bool isPrimaryKey, bool isIdentity, string typeName, object? dbType, string quotedSqlName, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, Type? clrType) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// if set to true is a computed column. - /// if set to true is a primary key. - /// if set to true [is identity]. - /// Name of the type. - /// Type used by the database. - /// Name of the quoted SQL. - /// Indicates if the column is nullable. - /// The maximum length. - /// The precision. - /// The scale. - /// Full name of the type. - /// The CLR type that matches this column's database type. - protected ColumnMetadata(string name, bool isComputed, bool isPrimaryKey, bool isIdentity, string typeName, object? dbType, string quotedSqlName, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, Type? clrType) - { - TypeName = typeName; - SqlName = name; - IsComputed = isComputed; - IsPrimaryKey = isPrimaryKey; - IsIdentity = isIdentity; - DbType = dbType; - QuotedSqlName = quotedSqlName; - - ClrName = Utilities.ToClrName(name); - SqlVariableName = "@" + ClrName; - - ClrType = clrType ?? typeof(object); - - IsNullable = isNullable; - Precision = precision; - MaxLength = maxLength; - Scale = scale; - FullTypeName = fullTypeName; - } + TypeName = typeName; + SqlName = name; + IsComputed = isComputed; + IsPrimaryKey = isPrimaryKey; + IsIdentity = isIdentity; + DbType = dbType; + QuotedSqlName = quotedSqlName; + + ClrName = Utilities.ToClrName(name); + SqlVariableName = "@" + ClrName; + + ClrType = clrType ?? typeof(object); + + IsNullable = isNullable; + Precision = precision; + MaxLength = maxLength; + Scale = scale; + FullTypeName = fullTypeName; + } + + /// + /// Gets the name used by CLR objects. + /// + public string ClrName { get; } - /// - /// Gets the name used by CLR objects. - /// - public string ClrName { get; } - - /// - /// The CLR type of the column or NULL if the type is unknown. - /// - public Type ClrType { get; } - - /// - /// Gets the type used by the database. - /// - public object? DbType { get; } - - /// - /// Gets or sets the full name of the type including max length, precision, and/or scale. - /// - /// - /// The full name of the type. - /// - public string FullTypeName { get; } - - /// - /// Gets a value indicating whether this is computed. - /// - /// - /// true if computed; otherwise, false. - /// - public bool IsComputed { get; } - - /// - /// Gets a value indicating whether this column is an identity column. - /// - /// true if this instance is identity; otherwise, false. - public bool IsIdentity { get; } - - /// - /// Gets or sets a value indicating whether this column is nullable. - /// - /// - /// true if this column is nullable; otherwise, false. - /// - public bool? IsNullable { get; } - - /// - /// Gets a value indicating whether this column is a primary key. - /// - /// true if this instance is primary key; otherwise, false. - public bool IsPrimaryKey { get; } - - /// - /// Gets or sets the maximum length. - /// - /// - /// The maximum length. - /// - public int? MaxLength { get; } - - /// - /// Gets or sets the precision. - /// - /// - /// The precision. - /// - public int? Precision { get; } - - /// - /// Gets the name used by SQL Server, quoted. - /// - public string QuotedSqlName { get; } - - /// - /// Gets or sets the scale. - /// - /// - /// The scale. - /// - public int? Scale { get; } - - /// - /// Gets the name used by the database. - /// - public string SqlName { get; } - - /// - /// Gets the column, formatted as a SQL variable. - /// - public string SqlVariableName { get; } - - /// - /// Gets the name of the type as known to the database. - /// - /// The name of the type as known to the database. - public string TypeName { get; } - - /// - /// Returns the CLR Type name suitable for code generation scenarios. - /// - /// Code generation options. - /// - public string ClrTypeName(NameGenerationOptions options) + /// + /// The CLR type of the column or NULL if the type is unknown. + /// + public Type ClrType { get; } + + /// + /// Gets the type used by the database. + /// + public object? DbType { get; } + + /// + /// Gets or sets the full name of the type including max length, precision, and/or scale. + /// + /// + /// The full name of the type. + /// + public string FullTypeName { get; } + + /// + /// Gets a value indicating whether this is computed. + /// + /// + /// true if computed; otherwise, false. + /// + public bool IsComputed { get; } + + /// + /// Gets a value indicating whether this column is an identity column. + /// + /// true if this instance is identity; otherwise, false. + public bool IsIdentity { get; } + + /// + /// Gets or sets a value indicating whether this column is nullable. + /// + /// + /// true if this column is nullable; otherwise, false. + /// + public bool? IsNullable { get; } + + /// + /// Gets a value indicating whether this column is a primary key. + /// + /// true if this instance is primary key; otherwise, false. + public bool IsPrimaryKey { get; } + + /// + /// Gets or sets the maximum length. + /// + /// + /// The maximum length. + /// + public int? MaxLength { get; } + + /// + /// Gets or sets the precision. + /// + /// + /// The precision. + /// + public int? Precision { get; } + + /// + /// Gets the name used by SQL Server, quoted. + /// + public string QuotedSqlName { get; } + + /// + /// Gets or sets the scale. + /// + /// + /// The scale. + /// + public int? Scale { get; } + + /// + /// Gets the name used by the database. + /// + public string SqlName { get; } + + /// + /// Gets the column, formatted as a SQL variable. + /// + public string SqlVariableName { get; } + + /// + /// Gets the name of the type as known to the database. + /// + /// The name of the type as known to the database. + public string TypeName { get; } + + /// + /// Returns the CLR Type name suitable for code generation scenarios. + /// + /// Code generation options. + /// + public string ClrTypeName(NameGenerationOptions options) + { + if (options.HasFlag(NameGenerationOptions.ForceNullable) && options.HasFlag(NameGenerationOptions.ForceNonNullable)) + throw new ArgumentException("Cannot specify both ForceNullable and ForceNonNullable", nameof(options)); + + var langCount = 0; + if (options.HasFlag(NameGenerationOptions.CSharp)) + langCount += 1; + if (options.HasFlag(NameGenerationOptions.VisualBasic)) + langCount += 1; + if (options.HasFlag(NameGenerationOptions.FSharp)) + langCount += 1; + if (langCount != 1) + throw new ArgumentException("Must specify one of CSharp, FSharp, or VisualBasic"); + + var metadata = MetadataCache.GetMetadata(ClrType); + + bool effectivelyNullable; + + if (options.HasFlag(NameGenerationOptions.ForceNullable)) + effectivelyNullable = true; + else if (options.HasFlag(NameGenerationOptions.ForceNonNullable)) + effectivelyNullable = false; + else if (IsNullable.HasValue) + effectivelyNullable = IsNullable.Value; + else + effectivelyNullable = options.HasFlag(NameGenerationOptions.AssumeNullable); + + string fullTypeName; + + if (options.HasFlag(NameGenerationOptions.CSharp)) + fullTypeName = metadata.CSharpFullName; + else if (options.HasFlag(NameGenerationOptions.VisualBasic)) + fullTypeName = metadata.VisualBasicFullName; + else if (options.HasFlag(NameGenerationOptions.FSharp)) + fullTypeName = metadata.FSharpFullName; + else + fullTypeName = ClrType.Name; + + //Make the data type nullable if necessary + if (options.HasFlag(NameGenerationOptions.CSharp) && options.HasFlag(NameGenerationOptions.NullableReferenceTypes)) { - if (options.HasFlag(NameGenerationOptions.ForceNullable) && options.HasFlag(NameGenerationOptions.ForceNonNullable)) - throw new ArgumentException("Cannot specify both ForceNullable and ForceNonNullable", nameof(options)); - - var langCount = 0; - if (options.HasFlag(NameGenerationOptions.CSharp)) - langCount += 1; - if (options.HasFlag(NameGenerationOptions.VisualBasic)) - langCount += 1; - if (options.HasFlag(NameGenerationOptions.FSharp)) - langCount += 1; - if (langCount != 1) - throw new ArgumentException("Must specify one of CSharp, FSharp, or VisualBasic"); - - var metadata = MetadataCache.GetMetadata(ClrType); - - bool effectivelyNullable; - - if (options.HasFlag(NameGenerationOptions.ForceNullable)) - effectivelyNullable = true; - else if (options.HasFlag(NameGenerationOptions.ForceNonNullable)) - effectivelyNullable = false; - else if (IsNullable.HasValue) - effectivelyNullable = IsNullable.Value; - else - effectivelyNullable = options.HasFlag(NameGenerationOptions.AssumeNullable); - - string fullTypeName; - - if (options.HasFlag(NameGenerationOptions.CSharp)) - fullTypeName = metadata.CSharpFullName; - else if (options.HasFlag(NameGenerationOptions.VisualBasic)) - fullTypeName = metadata.VisualBasicFullName; - else if (options.HasFlag(NameGenerationOptions.FSharp)) - fullTypeName = metadata.FSharpFullName; - else - fullTypeName = ClrType.Name; - - //Make the data type nullable if necessary - if (options.HasFlag(NameGenerationOptions.CSharp) && options.HasFlag(NameGenerationOptions.NullableReferenceTypes)) - { - //value types are handled upstream - if (!ClrType.IsValueType && effectivelyNullable) - fullTypeName += "?"; - } - - return fullTypeName; + //value types are handled upstream + if (!ClrType.IsValueType && effectivelyNullable) + fullTypeName += "?"; } + + return fullTypeName; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection.cs index 4874a069a..b4c00d7c8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection.cs @@ -1,83 +1,82 @@ using System.Collections; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class ColumnMetadataCollection. +/// +public class ColumnMetadataCollection : IReadOnlyList { + readonly IReadOnlyList m_Source; + + readonly string m_Name; + /// - /// Class ColumnMetadataCollection. + /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. /// - public class ColumnMetadataCollection : IReadOnlyList + /// The name of the parent object. + /// The source. + internal ColumnMetadataCollection(string name, IReadOnlyList source) { - readonly IReadOnlyList m_Source; + m_Name = name; + m_Source = source; + } - readonly string m_Name; + /// Gets the number of elements in the collection. + /// The number of elements in the collection. + public int Count => m_Source.Count; - /// - /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. - /// - /// The name of the parent object. - /// The source. - internal ColumnMetadataCollection(string name, IReadOnlyList source) - { - m_Name = name; - m_Source = source; - } + /// Gets the element at the specified index in the read-only list. + /// The zero-based index of the element to get. + /// The element at the specified index in the read-only list. + public ColumnMetadata this[int index] => m_Source[index]; - /// Gets the number of elements in the collection. - /// The number of elements in the collection. - public int Count => m_Source.Count; + /// Returns an enumerator that iterates through the collection. + /// An enumerator that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + return m_Source.GetEnumerator(); + } - /// Gets the element at the specified index in the read-only list. - /// The zero-based index of the element to get. - /// The element at the specified index in the read-only list. - public ColumnMetadata this[int index] => m_Source[index]; + IEnumerator IEnumerable.GetEnumerator() + { + return m_Source.GetEnumerator(); + } - /// Returns an enumerator that iterates through the collection. - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return m_Source.GetEnumerator(); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// If the column name was not found, this will return null + public ColumnMetadata? TryGetColumn(string columnName) + { + foreach (var item in this) + if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) + return item; - IEnumerator IEnumerable.GetEnumerator() - { - return m_Source.GetEnumerator(); - } + return null; + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// If the column name was not found, this will return null - public ColumnMetadata? TryGetColumn(string columnName) + /// + /// Gets the with the specified column name. + /// + /// + /// The . + /// + /// Name of the column. + /// + public ColumnMetadata this[string columnName] + { + get { foreach (var item in this) if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) return item; - return null; - } - - /// - /// Gets the with the specified column name. - /// - /// - /// The . - /// - /// Name of the column. - /// - public ColumnMetadata this[string columnName] - { - get - { - foreach (var item in this) - if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) - return item; - #pragma warning disable CA1065 // Do not raise exceptions in unexpected locations - throw new KeyNotFoundException($"Could not find column named {columnName} in object {m_Name}"); + throw new KeyNotFoundException($"Could not find column named {columnName} in object {m_Name}"); #pragma warning restore CA1065 // Do not raise exceptions in unexpected locations - } } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection`1.cs index c0fbea0ad..b32621095 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadataCollection`1.cs @@ -1,68 +1,67 @@ using System.Collections.ObjectModel; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Collection of Column Metadata +/// +/// The type of the database type. +public class ColumnMetadataCollection : ReadOnlyCollection> + where TDbType : struct { + readonly string m_Name; + /// - /// Collection of Column Metadata + /// Initializes a new instance of the class. /// - /// The type of the database type. - public class ColumnMetadataCollection : ReadOnlyCollection> - where TDbType : struct + /// The name of the parent object. + /// The list to wrap. + public ColumnMetadataCollection(string name, IList> list) : base(list) { - readonly string m_Name; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the parent object. - /// The list to wrap. - public ColumnMetadataCollection(string name, IList> list) : base(list) - { - m_Name = name; - GenericCollection = new ColumnMetadataCollection(name, this); - } - - /// - /// Gets the with the specified column name. - /// - /// - /// The . - /// - /// Name of the column. - /// - public ColumnMetadata this[string columnName] - { - get - { - foreach (var item in this) - if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) - return item; - -#pragma warning disable CA1065 // Do not raise exceptions in unexpected locations - throw new KeyNotFoundException($"Could not find column named {columnName} in object {m_Name}"); -#pragma warning restore CA1065 // Do not raise exceptions in unexpected locations - } - } + m_Name = name; + GenericCollection = new ColumnMetadataCollection(name, this); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// If the column name was not found, this will return null - public ColumnMetadata? TryGetColumn(string columnName) + /// + /// Gets the with the specified column name. + /// + /// + /// The . + /// + /// Name of the column. + /// + public ColumnMetadata this[string columnName] + { + get { foreach (var item in this) if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) return item; - return null; +#pragma warning disable CA1065 // Do not raise exceptions in unexpected locations + throw new KeyNotFoundException($"Could not find column named {columnName} in object {m_Name}"); +#pragma warning restore CA1065 // Do not raise exceptions in unexpected locations } + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// If the column name was not found, this will return null + public ColumnMetadata? TryGetColumn(string columnName) + { + foreach (var item in this) + if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) + return item; - /// - /// Gets the generic version of this collection. - /// - /// We can't make this implement IReadOnlyList because it breaks LINQ. - public ColumnMetadataCollection GenericCollection { get; } + return null; } + + /// + /// Gets the generic version of this collection. + /// + /// We can't make this implement IReadOnlyList because it breaks LINQ. + public ColumnMetadataCollection GenericCollection { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata`1.cs index c1225b53c..7a9002abe 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnMetadata`1.cs @@ -1,50 +1,49 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for a table or view column +/// +/// The variant of DbType used by this data source. +public sealed class ColumnMetadata : ColumnMetadata, ISqlBuilderEntryDetails +where TDbType : struct { /// - /// Metadata for a table or view column + /// Initializes a new instance of the class. /// - /// The variant of DbType used by this data source. - public sealed class ColumnMetadata : ColumnMetadata, ISqlBuilderEntryDetails - where TDbType : struct + /// The name. + /// if set to true is a computed column. + /// if set to true is a primary key. + /// if set to true [is identity]. + /// Name of the type. + /// Type used by the database. + /// Name of the quoted SQL. + /// Indicates if the column is nullable. + /// The maximum length. + /// The precision. + /// The scale. + /// Full name of the type. + /// The CLR type that matches this column's database type. + public ColumnMetadata(string name, bool isComputed, bool isPrimaryKey, bool isIdentity, string typeName, TDbType? dbType, string quotedSqlName, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, Type? clrType) : base(name, isComputed, isPrimaryKey, isIdentity, typeName, dbType, quotedSqlName, isNullable, maxLength, precision, scale, fullTypeName, clrType) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// if set to true is a computed column. - /// if set to true is a primary key. - /// if set to true [is identity]. - /// Name of the type. - /// Type used by the database. - /// Name of the quoted SQL. - /// Indicates if the column is nullable. - /// The maximum length. - /// The precision. - /// The scale. - /// Full name of the type. - /// The CLR type that matches this column's database type. - public ColumnMetadata(string name, bool isComputed, bool isPrimaryKey, bool isIdentity, string typeName, TDbType? dbType, string quotedSqlName, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, Type? clrType) : base(name, isComputed, isPrimaryKey, isIdentity, typeName, dbType, quotedSqlName, isNullable, maxLength, precision, scale, fullTypeName, clrType) - { - DbType = dbType; - } + DbType = dbType; + } - /// - /// Gets the type used by the database. - /// - public new TDbType? DbType { get; } + /// + /// Gets the type used by the database. + /// + public new TDbType? DbType { get; } - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() => SqlName + " (" + TypeName + ")"; + /// + /// Indicates the direction of the parameter. + /// + /// Only used for input parameters (e.g. filters) + ParameterDirection ISqlBuilderEntryDetails.Direction => ParameterDirection.Input; - /// - /// Indicates the direction of the parameter. - /// - /// Only used for input parameters (e.g. filters) - ParameterDirection ISqlBuilderEntryDetails.Direction => ParameterDirection.Input; - } + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() => SqlName + " (" + TypeName + ")"; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnNamePair.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnNamePair.cs index cdfcc4cc4..bbf3c7bbe 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnNamePair.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnNamePair.cs @@ -1,91 +1,90 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This is used to read out column names during SQL generation. +/// +public struct ColumnNamePair : IEquatable { /// - /// This is used to read out column names during SQL generation. + /// Initializes a new instance of the struct. /// - public struct ColumnNamePair : IEquatable + /// Name of the quoted SQL. + /// Name of the SQL variable. + public ColumnNamePair(string quotedSqlName, string sqlVariableName) { - /// - /// Initializes a new instance of the struct. - /// - /// Name of the quoted SQL. - /// Name of the SQL variable. - public ColumnNamePair(string quotedSqlName, string sqlVariableName) - { - QuotedSqlName = quotedSqlName; - SqlVariableName = sqlVariableName; - } + QuotedSqlName = quotedSqlName; + SqlVariableName = sqlVariableName; + } - /// - /// Gets or sets column name as quoted SQL. - /// - public string QuotedSqlName { get; } + /// + /// Gets or sets column name as quoted SQL. + /// + public string QuotedSqlName { get; } - /// - /// Gets or sets column name as a SQL variable. - /// - public string SqlVariableName { get; } + /// + /// Gets or sets column name as a SQL variable. + /// + public string SqlVariableName { get; } - /// - /// Implements the operator !=. - /// - /// The first. - /// The second. - /// - /// The result of the operator. - /// - public static bool operator !=(ColumnNamePair first, ColumnNamePair second) => !(first == second); + /// + /// Implements the operator !=. + /// + /// The first. + /// The second. + /// + /// The result of the operator. + /// + public static bool operator !=(ColumnNamePair first, ColumnNamePair second) => !(first == second); - /// - /// Implements the operator ==. - /// - /// The first. - /// The second. - /// - /// The result of the operator. - /// - public static bool operator ==(ColumnNamePair first, ColumnNamePair second) - { - return first.Equals(second); - } + /// + /// Implements the operator ==. + /// + /// The first. + /// The second. + /// + /// The result of the operator. + /// + public static bool operator ==(ColumnNamePair first, ColumnNamePair second) + { + return first.Equals(second); + } - /// - /// Determines whether the specified , is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - public override bool Equals(object? obj) - { - if (obj is ColumnNamePair columnNamePair) - return Equals(columnNamePair); - return base.Equals(obj); - } + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object? obj) + { + if (obj is ColumnNamePair columnNamePair) + return Equals(columnNamePair); + return base.Equals(obj); + } - /// - /// Indicates whether the current object is equal to another object of the same type. - /// - /// An object to compare with this object. - /// - /// true if the current object is equal to the parameter; otherwise, false. - /// - public bool Equals(ColumnNamePair other) => - string.Equals(QuotedSqlName, other.QuotedSqlName, StringComparison.Ordinal) - && string.Equals(SqlVariableName, other.SqlVariableName, StringComparison.Ordinal); + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// An object to compare with this object. + /// + /// true if the current object is equal to the parameter; otherwise, false. + /// + public bool Equals(ColumnNamePair other) => + string.Equals(QuotedSqlName, other.QuotedSqlName, StringComparison.Ordinal) + && string.Equals(SqlVariableName, other.SqlVariableName, StringComparison.Ordinal); - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - public override int GetHashCode() + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + unchecked { - unchecked - { - return QuotedSqlName.GetHashCode(StringComparison.Ordinal) ^ SqlVariableName.GetHashCode(StringComparison.Ordinal); - } + return QuotedSqlName.GetHashCode(StringComparison.Ordinal) ^ SqlVariableName.GetHashCode(StringComparison.Ordinal); } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnPropertyMap`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnPropertyMap`1.cs index 56a05ce23..4e435a027 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnPropertyMap`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ColumnPropertyMap`1.cs @@ -1,35 +1,34 @@ using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This maps database columns (tables and views) to class properties. +/// +/// The variant of DbType used by this data source. +public sealed class ColumnPropertyMap + where TDbType : struct { /// - /// This maps database columns (tables and views) to class properties. + /// Initializes a new instance of the class. /// - /// The variant of DbType used by this data source. - public sealed class ColumnPropertyMap - where TDbType : struct + /// The column. + /// The property. + public ColumnPropertyMap(ColumnMetadata column, PropertyMetadata property) { - /// - /// Initializes a new instance of the class. - /// - /// The column. - /// The property. - public ColumnPropertyMap(ColumnMetadata column, PropertyMetadata property) - { - Column = column; - Property = property; - } + Column = column; + Property = property; + } - /// - /// Gets the column. - /// - /// The column. - public ColumnMetadata Column { get; private set; } + /// + /// Gets the column. + /// + /// The column. + public ColumnMetadata Column { get; private set; } - /// - /// Gets the property. - /// - /// The property. - public PropertyMetadata Property { get; private set; } - } + /// + /// Gets the property. + /// + /// The property. + public PropertyMetadata Property { get; private set; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DatabaseMetadataCache`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DatabaseMetadataCache`2.cs index ac12c0af0..1460277d7 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DatabaseMetadataCache`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DatabaseMetadataCache`2.cs @@ -5,625 +5,636 @@ using Tortuga.Anchor; using Tortuga.Anchor.Metadata; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// An abstract database metadata cache +/// +/// The type used to represent database object names. +/// The variant of DbType used by this data source. +public abstract class DatabaseMetadataCache : IDatabaseMetadataCache + where TObjectName : struct + where TDbType : struct { /// - /// An abstract database metadata cache + /// This dictionary is used to register customer database types. It is used by the ToClrType method and possibly parameter generation. /// - /// The type used to represent database object names. - /// The variant of DbType used by this data source. - public abstract class DatabaseMetadataCache : IDatabaseMetadataCache - where TObjectName : struct - where TDbType : struct + /// This is populated by the RegisterType method. + readonly ConcurrentDictionary> m_RegisteredTypes = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); + + private readonly ConcurrentDictionary<(Type, OperationType), TableOrViewMetadata> m_TypeTableMap = new ConcurrentDictionary<(Type, OperationType), TableOrViewMetadata>(); + + /// + /// Gets the converter dictionary used by materializers. + /// + /// The converter dictionary. + public MaterializerTypeConverter Converter { get; } = new(); + + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + public virtual int? MaxParameters => null; + + /// + /// Get the maximum number of rows in a single SQL statement's Values clause. + /// + public virtual int? MaxRowsPerValuesClause => null; + + /// + /// Gets the server version number. + /// + public virtual Version? ServerVersion => null; + + /// + /// Gets the server version name. + /// + public virtual string? ServerVersionName => null; + + /// + /// Gets a list of known, unsupported SQL type names. + /// + /// Case-insensitive list of database-specific type names + /// This list is based on driver limitations. + public virtual ImmutableHashSet UnsupportedSqlTypeNames => ImmutableHashSet.Empty; + + /// + /// Gets the foreign keys for a table. + /// + /// Name of the table. + /// + /// Foreign keys are not supported by this data source + /// + /// This should be cached on a TableOrViewMetadata object. + /// + public virtual ForeignKeyConstraintCollection GetForeignKeysForTable(TObjectName tableName) { - /// - /// This dictionary is used to register customer database types. It is used by the ToClrType method and possibly parameter generation. - /// - /// This is populated by the RegisterType method. - readonly ConcurrentDictionary> m_RegisteredTypes = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); - - private readonly ConcurrentDictionary<(Type, OperationType), TableOrViewMetadata> m_TypeTableMap = new ConcurrentDictionary<(Type, OperationType), TableOrViewMetadata>(); - - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - public virtual int? MaxParameters => null; - - /// - /// Get the maximum number of rows in a single SQL statement's Values clause. - /// - public virtual int? MaxRowsPerValuesClause => null; - - /// - /// Gets the server version number. - /// - public virtual Version? ServerVersion => null; - - /// - /// Gets the server version name. - /// - public virtual string? ServerVersionName => null; - - /// - /// Gets a list of known, unsupported SQL type names. - /// - /// Case-insensitive list of database-specific type names - /// This list is based on driver limitations. - public virtual ImmutableHashSet UnsupportedSqlTypeNames => ImmutableHashSet.Empty; - - /// - /// Gets the foreign keys for a table. - /// - /// Name of the table. - /// - /// Foreign keys are not supported by this data source - /// - /// This should be cached on a TableOrViewMetadata object. - /// - public virtual ForeignKeyConstraintCollection GetForeignKeysForTable(TObjectName tableName) - { - throw new NotSupportedException("Foreign Keys are not supported by this data source"); - } + throw new NotSupportedException("Foreign Keys are not supported by this data source"); + } - /// - /// Gets the indexes for a table. - /// - /// Name of the table. - /// - /// Indexes are not supported by this data source - /// - /// This should be cached on a TableOrViewMetadata object. - /// - public virtual IndexMetadataCollection GetIndexesForTable(TObjectName tableName) - { - throw new NotSupportedException("Indexes are not supported by this data source"); - } + /// + /// Gets the indexes for a table. + /// + /// Name of the table. + /// + /// Indexes are not supported by this data source + /// + /// This should be cached on a TableOrViewMetadata object. + /// + public virtual IndexMetadataCollection GetIndexesForTable(TObjectName tableName) + { + throw new NotSupportedException("Indexes are not supported by this data source"); + } - /// - /// Gets the metadata for a scalar function. - /// - /// Name of the scalar function. - /// Null if the object could not be found. - public virtual ScalarFunctionMetadata GetScalarFunction(TObjectName scalarFunctionName) - { - throw new NotSupportedException("Table value functions are not supported by this data source"); - } + ///// + ///// Gets the parameters from a SQL Builder. + ///// + ///// The SQL builder. + ///// + //public List GetParameters(SqlBuilder sqlBuilder) + //{ + // return sqlBuilder.GetParameters(ParameterBuilderCallback); + //} - /// - /// Gets the scalar functions that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public virtual IReadOnlyCollection> GetScalarFunctions() - { - throw new NotSupportedException("Table value functions are not supported by this data source"); - } + /// + /// Gets the metadata for a scalar function. + /// + /// Name of the scalar function. + /// Null if the object could not be found. + public virtual ScalarFunctionMetadata GetScalarFunction(TObjectName scalarFunctionName) + { + throw new NotSupportedException("Table value functions are not supported by this data source"); + } - /// - /// Gets the stored procedure's metadata. - /// - /// Name of the procedure. - /// - public virtual StoredProcedureMetadata GetStoredProcedure(TObjectName procedureName) - { - throw new NotSupportedException("Stored procedures are not supported by this data source"); - } + /// + /// Gets the scalar functions that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public virtual IReadOnlyCollection> GetScalarFunctions() + { + throw new NotSupportedException("Table value functions are not supported by this data source"); + } - StoredProcedureMetadata IDatabaseMetadataCache.GetStoredProcedure(string procedureName) - { - return GetStoredProcedure(ParseObjectName(procedureName)); - } + /// + /// Gets the stored procedure's metadata. + /// + /// Name of the procedure. + /// + public virtual StoredProcedureMetadata GetStoredProcedure(TObjectName procedureName) + { + throw new NotSupportedException("Stored procedures are not supported by this data source"); + } - /// - /// Gets the stored procedures that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public virtual IReadOnlyCollection> GetStoredProcedures() - { - throw new NotSupportedException("Stored procedures are not supported by this data source"); - } + StoredProcedureMetadata IDatabaseMetadataCache.GetStoredProcedure(string procedureName) + { + return GetStoredProcedure(ParseObjectName(procedureName)); + } - IReadOnlyCollection IDatabaseMetadataCache.GetStoredProcedures() - { - return GetStoredProcedures(); - } + /// + /// Gets the stored procedures that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public virtual IReadOnlyCollection> GetStoredProcedures() + { + throw new NotSupportedException("Stored procedures are not supported by this data source"); + } - /// - /// Gets the metadata for a table function. - /// - /// Name of the table function. - public virtual TableFunctionMetadata GetTableFunction(TObjectName tableFunctionName) - { - throw new NotSupportedException("Table value functions are not supported by this data source"); - } + IReadOnlyCollection IDatabaseMetadataCache.GetStoredProcedures() + { + return GetStoredProcedures(); + } - TableFunctionMetadata IDatabaseMetadataCache.GetTableFunction(string tableFunctionName) - { - return GetTableFunction(ParseObjectName(tableFunctionName)); - } + /// + /// Gets the metadata for a table function. + /// + /// Name of the table function. + public virtual TableFunctionMetadata GetTableFunction(TObjectName tableFunctionName) + { + throw new NotSupportedException("Table value functions are not supported by this data source"); + } - /// - /// Gets the table-valued functions that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public virtual IReadOnlyCollection> GetTableFunctions() - { - throw new NotSupportedException("Table value functions are not supported by this data source"); - } + TableFunctionMetadata IDatabaseMetadataCache.GetTableFunction(string tableFunctionName) + { + return GetTableFunction(ParseObjectName(tableFunctionName)); + } + + /// + /// Gets the table-valued functions that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public virtual IReadOnlyCollection> GetTableFunctions() + { + throw new NotSupportedException("Table value functions are not supported by this data source"); + } - IReadOnlyCollection IDatabaseMetadataCache.GetTableFunctions() => GetTableFunctions(); + IReadOnlyCollection IDatabaseMetadataCache.GetTableFunctions() => GetTableFunctions(); - /// - /// Gets the metadata for a table. - /// - /// Name of the table. - /// - public abstract TableOrViewMetadata GetTableOrView(TObjectName tableName); + /// + /// Gets the metadata for a table. + /// + /// Name of the table. + /// + public abstract TableOrViewMetadata GetTableOrView(TObjectName tableName); + + TableOrViewMetadata IDatabaseMetadataCache.GetTableOrView(string tableName) => GetTableOrView(ParseObjectName(tableName)); + + /// + /// Returns the table or view derived from the class's name and/or Table attribute. + /// + /// The type of the object. + /// The operation. + /// DatabaseObject. + public TableOrViewMetadata GetTableOrViewFromClass(OperationType operation = OperationType.All) + { + var type = typeof(TObject); + return GetTableOrViewFromClass(type, operation); + } - TableOrViewMetadata IDatabaseMetadataCache.GetTableOrView(string tableName) => GetTableOrView(ParseObjectName(tableName)); + /// + /// Returns the table or view derived from the class's name and/or Table attribute. + /// + /// + /// The operation. + /// DatabaseObject. + public TableOrViewMetadata GetTableOrViewFromClass(Type type, OperationType operation = OperationType.All) + { + var cacheKey = (type, operation); + + if (m_TypeTableMap.TryGetValue(cacheKey, out var cachedResult)) + return cachedResult; + //This section uses the TableAttribute or TableAndViewAttribute from the class. + var typeInfo = MetadataCache.GetMetadata(type); + var objectName = typeInfo.MappedTableName; + var schemaName = typeInfo.MappedSchemaName; - /// - /// Returns the table or view derived from the class's name and/or Table attribute. - /// - /// The type of the object. - /// The operation. - /// DatabaseObject. - public TableOrViewMetadata GetTableOrViewFromClass(OperationType operation = OperationType.All) + //On reads we can use the view instead. + if (operation == OperationType.Select) { - var type = typeof(TObject); - return GetTableOrViewFromClass(type, operation); + objectName = typeInfo.MappedViewName ?? objectName; + schemaName = typeInfo.MappedViewSchemaName ?? schemaName; } - /// - /// Returns the table or view derived from the class's name and/or Table attribute. - /// - /// - /// The operation. - /// DatabaseObject. - public TableOrViewMetadata GetTableOrViewFromClass(Type type, OperationType operation = OperationType.All) + if (!objectName.IsNullOrEmpty()) { - var cacheKey = (type, operation); + var name = schemaName.IsNullOrEmpty() ? ParseObjectName(objectName) : ParseObjectName(schemaName, objectName); - if (m_TypeTableMap.TryGetValue(cacheKey, out var cachedResult)) - return cachedResult; - - //This section uses the TableAttribute or TableAndViewAttribute from the class. - var typeInfo = MetadataCache.GetMetadata(type); - var objectName = typeInfo.MappedTableName; - var schemaName = typeInfo.MappedSchemaName; - - //On reads we can use the view instead. - if (operation == OperationType.Select) + if (TryGetTableOrView(name, out var tableResult)) { - objectName = typeInfo.MappedViewName ?? objectName; - schemaName = typeInfo.MappedViewSchemaName ?? schemaName; + m_TypeTableMap[cacheKey] = tableResult; + return tableResult; } - if (!objectName.IsNullOrEmpty()) - { - var name = schemaName.IsNullOrEmpty() ? ParseObjectName(objectName) : ParseObjectName(schemaName, objectName); + throw new MissingObjectException($"Cannot find a table or view with the name {name}"); + } - if (TryGetTableOrView(name, out var tableResult)) - { - m_TypeTableMap[cacheKey] = tableResult; - return tableResult; - } + //This section infers the schema from namespace + { + var schema = type.Namespace; + if (schema != null && schema.Contains(".", StringComparison.Ordinal)) + schema = schema.Substring(schema.LastIndexOf(".", StringComparison.Ordinal) + 1); + + var nameA = ParseObjectName(schema, type.Name); + var nameB = ParseObjectName(null, type.Name); - throw new MissingObjectException($"Cannot find a table or view with the name {name}"); + if (TryGetTableOrView(nameA, out var tableResult)) + { + m_TypeTableMap[cacheKey] = tableResult; + return tableResult; } - //This section infers the schema from namespace + //that didn't work, so try the default schema + if (TryGetTableOrView(nameB, out var tableResult2)) { - var schema = type.Namespace; - if (schema != null && schema.Contains(".", StringComparison.Ordinal)) - schema = schema.Substring(schema.LastIndexOf(".", StringComparison.Ordinal) + 1); - - var nameA = ParseObjectName(schema, type.Name); - var nameB = ParseObjectName(null, type.Name); - - if (TryGetTableOrView(nameA, out var tableResult)) - { - m_TypeTableMap[cacheKey] = tableResult; - return tableResult; - } - - //that didn't work, so try the default schema - if (TryGetTableOrView(nameB, out var tableResult2)) - { - m_TypeTableMap[cacheKey] = tableResult2; - return tableResult2; - } - - throw new MissingObjectException($"Cannot find a table or view with the name '{nameA}' or '{nameB}'"); + m_TypeTableMap[cacheKey] = tableResult2; + return tableResult2; } + + throw new MissingObjectException($"Cannot find a table or view with the name '{nameA}' or '{nameB}'"); } + } + TableOrViewMetadata IDatabaseMetadataCache.GetTableOrViewFromClass(OperationType operation) + => GetTableOrViewFromClass(operation); - /// DatabaseObject - /// Gets the tables and views that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public abstract IReadOnlyCollection> GetTablesAndViews(); + TableOrViewMetadata IDatabaseMetadataCache.GetTableOrViewFromClass(Type type, OperationType operation) + => GetTableOrViewFromClass(type, operation); - IReadOnlyCollection IDatabaseMetadataCache.GetTablesAndViews() => GetTablesAndViews(); + /// DatabaseObject + /// Gets the tables and views that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public abstract IReadOnlyCollection> GetTablesAndViews(); - /// - /// Gets the metadata for a user defined type. - /// - /// Name of the type. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public virtual UserDefinedTableTypeMetadata GetUserDefinedTableType(TObjectName typeName) - { - throw new NotSupportedException("User defined types are not supported by this data source"); - } + IReadOnlyCollection IDatabaseMetadataCache.GetTablesAndViews() => GetTablesAndViews(); - UserDefinedTableTypeMetadata IDatabaseMetadataCache.GetUserDefinedTableType(string typeName) => GetUserDefinedTableType(ParseObjectName(typeName)); + /// + /// Gets the metadata for a user defined type. + /// + /// Name of the type. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public virtual UserDefinedTableTypeMetadata GetUserDefinedTableType(TObjectName typeName) + { + throw new NotSupportedException("User defined types are not supported by this data source"); + } - IReadOnlyCollection IDatabaseMetadataCache.GetUserDefinedTableTypes() => GetUserDefinedTableTypes(); + UserDefinedTableTypeMetadata IDatabaseMetadataCache.GetUserDefinedTableType(string typeName) => GetUserDefinedTableType(ParseObjectName(typeName)); - /// - /// Gets the table-valued functions that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public virtual IReadOnlyCollection> GetUserDefinedTableTypes() + IReadOnlyCollection IDatabaseMetadataCache.GetUserDefinedTableTypes() => GetUserDefinedTableTypes(); + + /// + /// Gets the table-valued functions that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public virtual IReadOnlyCollection> GetUserDefinedTableTypes() + { + throw new NotSupportedException("Table value functions are not supported by this data source"); + } + + /// + /// Parse a string and return the database specific representation of the database object's name. + /// + /// + public TObjectName ParseObjectName(string name) => ParseObjectName(null, name); + + /// + /// Preloads all of the metadata for this data source. + /// + public abstract void Preload(); + + /// + /// Registers a database type and its CLR equivalent. + /// + /// Name of the database type. + /// Type of the database. + /// Type of the color. + public void RegisterType(string databaseTypeName, TDbType databaseType, Type clrType) + { + m_RegisteredTypes[databaseTypeName] = new TypeRegistration(databaseTypeName, databaseType, clrType); + } + + /// + /// Resets the metadata cache, clearing out all cached metadata. + /// + public virtual void Reset() + { + m_TypeTableMap.Clear(); + } + + /// + /// Returns the CLR type that matches the indicated database column type. + /// + /// Name of the database column type. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. + /// Indicates whether or not the column is unsigned. Only applicable to some databases. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// Use RegisterType to add a missing mapping or override an existing one. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public Type? ToClrType(string typeName, bool isNullable, int? maxLength, bool? isUnsigned = null) + { + if (TryGetRegisteredType(typeName, out var registeredType)) + return registeredType.ClrType; + + var dbType = SqlTypeNameToDbType(typeName, isUnsigned); + + if (dbType.HasValue) + return ToClrType(dbType.Value, isNullable, maxLength); + + return null; + } + + /// + /// Tries to get the metadata for a scalar function. + /// + /// Name of the scalar function. + /// The scalar function. + /// + public bool TryGetScalarFunction(string tableFunctionName, [NotNullWhen(true)] out ScalarFunctionMetadata? tableFunction) => + TryGetScalarFunction(ParseObjectName(tableFunctionName), out tableFunction); + + /// + /// Tries to get the metadata for a scalar function. + /// + /// Name of the scalar function. + /// The scalar function. + /// + public bool TryGetScalarFunction(TObjectName scalarFunctionName, [NotNullWhen(true)] out ScalarFunctionMetadata? scalarFunction) + { + try { - throw new NotSupportedException("Table value functions are not supported by this data source"); + scalarFunction = GetScalarFunction(scalarFunctionName); + return true; } - - /// - /// Preloads all of the metadata for this data source. - /// - public abstract void Preload(); - - /// - /// Registers a database type and its CLR equivalent. - /// - /// Name of the database type. - /// Type of the database. - /// Type of the color. - public void RegisterType(string databaseTypeName, TDbType databaseType, Type clrType) + catch (MissingObjectException) { - m_RegisteredTypes[databaseTypeName] = new TypeRegistration(databaseTypeName, databaseType, clrType); + scalarFunction = null; + return false; } - - /// - /// Resets the metadata cache, clearing out all cached metadata. - /// - public virtual void Reset() + catch (NotSupportedException) { - m_TypeTableMap.Clear(); + scalarFunction = null; + return false; } + } - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Name of the database column type. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. - /// Indicates whether or not the column is unsigned. Only applicable to some databases. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// Use RegisterType to add a missing mapping or override an existing one. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public Type? ToClrType(string typeName, bool isNullable, int? maxLength, bool? isUnsigned = null) - { - if (TryGetRegisteredType(typeName, out var registeredType)) - return registeredType.ClrType; + /// + /// Tries to get the stored procedure's metadata. + /// + /// Name of the procedure. + /// The stored procedure. + /// + public bool TryGetStoredProcedure(string procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure) => + TryGetStoredProcedure(ParseObjectName(procedureName), out storedProcedure); - var dbType = SqlTypeNameToDbType(typeName, isUnsigned); + /// + /// Tries to get the stored procedure's metadata. + /// + /// Name of the procedure. + /// The stored procedure. + /// + public bool TryGetStoredProcedure(TObjectName procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure) + { + try + { + storedProcedure = GetStoredProcedure(procedureName); + return true; + } + catch (MissingObjectException) + { + storedProcedure = null; + return false; + } + catch (NotSupportedException) + { + storedProcedure = null; + return false; + } + } - if (dbType.HasValue) - return ToClrType(dbType.Value, isNullable, maxLength); + /// + /// Tries to get the metadata for a table function. + /// + /// Name of the table function. + /// The table function. + /// + public bool TryGetTableFunction(string tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction) => + TryGetTableFunction(ParseObjectName(tableFunctionName), out tableFunction); - return null; + /// + /// Tries to get the metadata for a table function. + /// + /// Name of the table function. + /// The table function. + /// + public bool TryGetTableFunction(TObjectName tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction) + { + try + { + tableFunction = GetTableFunction(tableFunctionName); + return true; } - - /// - /// Tries to get the stored procedure's metadata. - /// - /// Name of the procedure. - /// The stored procedure. - /// - public bool TryGetStoredProcedure(string procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure) => - TryGetStoredProcedure(ParseObjectName(procedureName), out storedProcedure); - - /// - /// Tries to get the stored procedure's metadata. - /// - /// Name of the procedure. - /// The stored procedure. - /// - public bool TryGetStoredProcedure(TObjectName procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure) + catch (MissingObjectException) { - try - { - storedProcedure = GetStoredProcedure(procedureName); - return true; - } - catch (MissingObjectException) - { - storedProcedure = null; - return false; - } - catch (NotSupportedException) - { - storedProcedure = null; - return false; - } + tableFunction = null; + return false; } - - /// - /// Tries to get the metadata for a table function. - /// - /// Name of the table function. - /// The table function. - /// - public bool TryGetTableFunction(string tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction) => - TryGetTableFunction(ParseObjectName(tableFunctionName), out tableFunction); - - /// - /// Tries to get the metadata for a table function. - /// - /// Name of the table function. - /// The table function. - /// - public bool TryGetTableFunction(TObjectName tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction) + catch (NotSupportedException) { - try - { - tableFunction = GetTableFunction(tableFunctionName); - return true; - } - catch (MissingObjectException) - { - tableFunction = null; - return false; - } - catch (NotSupportedException) - { - tableFunction = null; - return false; - } + tableFunction = null; + return false; } + } - /// - /// Tries to get the metadata for a scalar function. - /// - /// Name of the scalar function. - /// The scalar function. - /// - public bool TryGetScalarFunction(string tableFunctionName, [NotNullWhen(true)] out ScalarFunctionMetadata? tableFunction) => - TryGetScalarFunction(ParseObjectName(tableFunctionName), out tableFunction); - - /// - /// Tries to get the metadata for a scalar function. - /// - /// Name of the scalar function. - /// The scalar function. - /// - public bool TryGetScalarFunction(TObjectName scalarFunctionName, [NotNullWhen(true)] out ScalarFunctionMetadata? scalarFunction) + /// + /// Tries to get the metadata for a table or view. + /// + /// Name of the table or view. + /// The table or view. + /// + bool IDatabaseMetadataCache.TryGetTableOrView(string tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView) + { + if (TryGetTableOrView(ParseObjectName(tableName), out var result)) { - try - { - scalarFunction = GetScalarFunction(scalarFunctionName); - return true; - } - catch (MissingObjectException) - { - scalarFunction = null; - return false; - } - catch (NotSupportedException) - { - scalarFunction = null; - return false; - } + tableOrView = result; + return true; } + tableOrView = null; + return false; + } - /// - /// Tries to get the metadata for a table or view. - /// - /// Name of the table or view. - /// The table or view. - /// - bool IDatabaseMetadataCache.TryGetTableOrView(string tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView) + /// + /// Tries to get the metadata for a table or view. + /// + /// Name of the table or view. + /// The table or view. + /// + public bool TryGetTableOrView(TObjectName tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView) + { + try + { + tableOrView = GetTableOrView(tableName); + return true; + } + catch (MissingObjectException) { - - if (TryGetTableOrView(ParseObjectName(tableName), out var result)) - { - tableOrView = result; - return true; - } tableOrView = null; return false; } - - /// - /// Tries to get the metadata for a table or view. - /// - /// Name of the table or view. - /// The table or view. - /// - public bool TryGetTableOrView(TObjectName tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView) + catch (NotSupportedException) { - try - { - tableOrView = GetTableOrView(tableName); - return true; - } - catch (MissingObjectException) - { - tableOrView = null; - return false; - } - catch (NotSupportedException) - { - tableOrView = null; - return false; - } + tableOrView = null; + return false; } + } + + /// + /// Try to get the metadata for a user defined type. + /// + /// Name of the type. + /// Type of the user defined table type. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public bool TryGetUserDefinedTableType(string typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType) => + TryGetUserDefinedTableType(ParseObjectName(typeName), out userDefinedTableType); - /// - /// Try to get the metadata for a user defined type. - /// - /// Name of the type. - /// Type of the user defined table type. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public bool TryGetUserDefinedTableType(string typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType) => - TryGetUserDefinedTableType(ParseObjectName(typeName), out userDefinedTableType); - - /// - /// Try to get the metadata for a user defined type. - /// - /// Name of the type. - /// Type of the user defined. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public bool TryGetUserDefinedTableType(TObjectName typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType) + /// + /// Try to get the metadata for a user defined type. + /// + /// Name of the type. + /// Type of the user defined. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public bool TryGetUserDefinedTableType(TObjectName typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType) + { + try { - try - { - userDefinedTableType = GetUserDefinedTableType(typeName); - return true; - } - catch (MissingObjectException) - { - userDefinedTableType = null; - return false; - } - catch (NotSupportedException) - { - userDefinedTableType = null; - return false; - } + userDefinedTableType = GetUserDefinedTableType(typeName); + return true; } - - /// - /// Removes a database type registration and its CLR equivalent. If a builtin type, this restores it to its default behavior. - /// - /// Name of the database type. - /// True if the type was successfully unregistered. False if the type was not found. - public bool UnregisterType(string databaseTypeName) + catch (MissingObjectException) { - return m_RegisteredTypes.TryRemove(databaseTypeName, out var _); + userDefinedTableType = null; + return false; } - - /// - /// Converts a value to a string suitable for use in a SQL statement. - /// - /// The value. - /// Optional database column type. - /// - /// Override this to support custom escaping logic. - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "dbType")] - [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "")] - public virtual string ValueToSqlValue(object value, TDbType? dbType) + catch (NotSupportedException) { - switch (value) - { - case DBNull _: - case System.Reflection.Missing _: - case null: - return "NULL"; - - case byte _: - case sbyte _: - case short _: - case ushort _: - case int _: - case uint _: - case long _: - case ulong _: - case decimal _: - case float _: - case double _: - return value.ToString()!; - - case string s: - return "'" + s.Replace("'", "''", StringComparison.Ordinal) + "'"; - - case DateTime d: - return "'" + d.ToString("O", CultureInfo.InvariantCulture) + "'"; //ISO 8601 - - case DateTimeOffset d: - return "'" + d.ToString("O", CultureInfo.InvariantCulture) + "'"; //ISO 8601 - - case TimeSpan ts: - return "'" + ts.ToString("hh:mm:ss.fffffff", CultureInfo.InvariantCulture) + "'"; //ISO 8601 - - default: - if (dbType.HasValue) - throw new NotSupportedException($"Converting a value of type {value.GetType().Name} into a string of type {dbType.ToString()} is not supported. Try filing a bug report."); - else - throw new NotSupportedException($"Converting a value of type {value.GetType().Name} is not supported. Try supplying a dbType or filing a bug report."); - } + userDefinedTableType = null; + return false; } + } - /// - /// Parse a string and return the database specific representation of the database object's name. - /// - /// - public TObjectName ParseObjectName(string name) => ParseObjectName(null, name); - - /// - /// Parse a string and return the database specific representation of the database object's name. - /// - /// - /// - protected abstract TObjectName ParseObjectName(string? schema, string name); - - /// - /// Determines the database column type from the column type name. - /// - /// Name of the database column type. - /// Indicates whether or not the column is unsigned. Only applicable to some databases. - /// - /// This does not honor registered types. This is only used for the database's hard-coded list of native types. - protected abstract TDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned); - - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Type of the database column. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. Defaults to string. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// This does not take into consideration registered types. - protected abstract Type? ToClrType(TDbType dbType, bool isNullable, int? maxLength); - - /// - /// Tries the registered column type from a database column type name. - /// - /// Name of the database type. - /// Type of the registered. - /// - protected bool TryGetRegisteredType(string databaseTypeName, [NotNullWhen(true)] out TypeRegistration? registeredType) + /// + /// Removes a database type registration and its CLR equivalent. If a builtin type, this restores it to its default behavior. + /// + /// Name of the database type. + /// True if the type was successfully unregistered. False if the type was not found. + public bool UnregisterType(string databaseTypeName) + { + return m_RegisteredTypes.TryRemove(databaseTypeName, out var _); + } + + /// + /// Converts a value to a string suitable for use in a SQL statement. + /// + /// The value. + /// Optional database column type. + /// + /// Override this to support custom escaping logic. + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "dbType")] + [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "")] + public virtual string ValueToSqlValue(object value, TDbType? dbType) + { + switch (value) { - return m_RegisteredTypes.TryGetValue(databaseTypeName, out registeredType!); + case DBNull _: + case System.Reflection.Missing _: + case null: + return "NULL"; + + case byte _: + case sbyte _: + case short _: + case ushort _: + case int _: + case uint _: + case long _: + case ulong _: + case decimal _: + case float _: + case double _: + return value.ToString()!; + + case string s: + return "'" + s.Replace("'", "''", StringComparison.Ordinal) + "'"; + + case DateTime d: + return "'" + d.ToString("O", CultureInfo.InvariantCulture) + "'"; //ISO 8601 + + case DateTimeOffset d: + return "'" + d.ToString("O", CultureInfo.InvariantCulture) + "'"; //ISO 8601 + + case TimeSpan ts: + return "'" + ts.ToString("hh:mm:ss.fffffff", CultureInfo.InvariantCulture) + "'"; //ISO 8601 + + default: + if (dbType.HasValue) + throw new NotSupportedException($"Converting a value of type {value.GetType().Name} into a string of type {dbType.ToString()} is not supported. Try filing a bug report."); + else + throw new NotSupportedException($"Converting a value of type {value.GetType().Name} is not supported. Try supplying a dbType or filing a bug report."); } + } - TableOrViewMetadata IDatabaseMetadataCache.GetTableOrViewFromClass(OperationType operation) - => GetTableOrViewFromClass(operation); + /// + /// Parse a string and return the database specific representation of the database object's name. + /// + /// + /// + protected abstract TObjectName ParseObjectName(string? schema, string name); - TableOrViewMetadata IDatabaseMetadataCache.GetTableOrViewFromClass(Type type, OperationType operation) - => GetTableOrViewFromClass(type, operation); + /// + /// Determines the database column type from the column type name. + /// + /// Name of the database column type. + /// Indicates whether or not the column is unsigned. Only applicable to some databases. + /// + /// This does not honor registered types. This is only used for the database's hard-coded list of native types. + protected abstract TDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned); + + /// + /// Returns the CLR type that matches the indicated database column type. + /// + /// Type of the database column. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. Defaults to string. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// This does not take into consideration registered types. + protected abstract Type? ToClrType(TDbType dbType, bool isNullable, int? maxLength); + /// + /// Tries the registered column type from a database column type name. + /// + /// Name of the database type. + /// Type of the registered. + /// + protected bool TryGetRegisteredType(string databaseTypeName, [NotNullWhen(true)] out TypeRegistration? registeredType) + { + return m_RegisteredTypes.TryGetValue(databaseTypeName, out registeredType!); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DbDatabaseMetadataCache`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DbDatabaseMetadataCache`1.cs index cab9ac540..0d90d603d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DbDatabaseMetadataCache`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/DbDatabaseMetadataCache`1.cs @@ -1,97 +1,96 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Meatadata cache base class for DbType databases +/// +/// The type used to represent database object names. +public abstract class DbDatabaseMetadataCache : DatabaseMetadataCache + where TObjectName : struct { /// - /// Meatadata cache base class for DbType databases + /// Returns the CLR type that matches the indicated database column type. /// - /// The type used to represent database object names. - public abstract class DbDatabaseMetadataCache : DatabaseMetadataCache - where TObjectName : struct + /// Type of the database column. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. Defaults to string. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// + /// This does not take into consideration registered types. + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502")] + protected override Type? ToClrType(DbType dbType, bool isNullable, int? maxLength) { - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Type of the database column. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. Defaults to string. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// - /// This does not take into consideration registered types. - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - protected override Type? ToClrType(DbType dbType, bool isNullable, int? maxLength) + switch (dbType) { - switch (dbType) - { - case DbType.AnsiString: - case DbType.AnsiStringFixedLength: - case DbType.StringFixedLength: - case DbType.String: - return (maxLength == 1) ? (isNullable ? typeof(char?) : typeof(char)) : typeof(string); + case DbType.AnsiString: + case DbType.AnsiStringFixedLength: + case DbType.StringFixedLength: + case DbType.String: + return (maxLength == 1) ? (isNullable ? typeof(char?) : typeof(char)) : typeof(string); - case DbType.Binary: - return typeof(byte[]); + case DbType.Binary: + return typeof(byte[]); - case DbType.Byte: - return isNullable ? typeof(byte?) : typeof(byte); + case DbType.Byte: + return isNullable ? typeof(byte?) : typeof(byte); - case DbType.Boolean: - return isNullable ? typeof(bool?) : typeof(bool); + case DbType.Boolean: + return isNullable ? typeof(bool?) : typeof(bool); - case DbType.Currency: - case DbType.Decimal: - case DbType.VarNumeric: - return isNullable ? typeof(decimal?) : typeof(decimal); + case DbType.Currency: + case DbType.Decimal: + case DbType.VarNumeric: + return isNullable ? typeof(decimal?) : typeof(decimal); - case DbType.Date: - case DbType.DateTime: - case DbType.DateTime2: - case DbType.Time: - return isNullable ? typeof(DateTime?) : typeof(DateTime); + case DbType.Date: + case DbType.DateTime: + case DbType.DateTime2: + case DbType.Time: + return isNullable ? typeof(DateTime?) : typeof(DateTime); - case DbType.Double: - return isNullable ? typeof(double?) : typeof(double); + case DbType.Double: + return isNullable ? typeof(double?) : typeof(double); - case DbType.Guid: - return isNullable ? typeof(Guid?) : typeof(Guid); + case DbType.Guid: + return isNullable ? typeof(Guid?) : typeof(Guid); - case DbType.Int16: - return isNullable ? typeof(short?) : typeof(short); + case DbType.Int16: + return isNullable ? typeof(short?) : typeof(short); - case DbType.Int32: - return isNullable ? typeof(int?) : typeof(int); + case DbType.Int32: + return isNullable ? typeof(int?) : typeof(int); - case DbType.Int64: - return isNullable ? typeof(long?) : typeof(long); + case DbType.Int64: + return isNullable ? typeof(long?) : typeof(long); - case DbType.Object: - return typeof(object); + case DbType.Object: + return typeof(object); - case DbType.SByte: - return isNullable ? typeof(sbyte?) : typeof(sbyte); + case DbType.SByte: + return isNullable ? typeof(sbyte?) : typeof(sbyte); - case DbType.Single: - return isNullable ? typeof(float?) : typeof(float); + case DbType.Single: + return isNullable ? typeof(float?) : typeof(float); - case DbType.UInt16: - return isNullable ? typeof(ushort?) : typeof(ushort); + case DbType.UInt16: + return isNullable ? typeof(ushort?) : typeof(ushort); - case DbType.UInt32: - return isNullable ? typeof(uint?) : typeof(uint); + case DbType.UInt32: + return isNullable ? typeof(uint?) : typeof(uint); - case DbType.UInt64: - return isNullable ? typeof(ulong?) : typeof(ulong); + case DbType.UInt64: + return isNullable ? typeof(ulong?) : typeof(ulong); - case DbType.Xml: - return typeof(string); + case DbType.Xml: + return typeof(string); - case DbType.DateTimeOffset: - return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); - } - return null; + case DbType.DateTimeOffset: + return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); } + return null; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint.cs index 5b0abbbfe..55bd57fe6 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint.cs @@ -1,54 +1,53 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This represents a foreign key relationship between two tables. +/// +public abstract class ForeignKeyConstraint { /// - /// This represents a foreign key relationship between two tables. + /// Initializes a new instance of the class. /// - public abstract class ForeignKeyConstraint + /// Name of the parent table. + /// The parent columns. + /// Name of the child table. + /// The child columns. + /// + /// parentColumns + /// or + /// childColumns + /// + protected ForeignKeyConstraint(string parentTableName, ColumnMetadataCollection parentColumns, string childTableName, ColumnMetadataCollection childColumns) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the parent table. - /// The parent columns. - /// Name of the child table. - /// The child columns. - /// - /// parentColumns - /// or - /// childColumns - /// - protected ForeignKeyConstraint(string parentTableName, ColumnMetadataCollection parentColumns, string childTableName, ColumnMetadataCollection childColumns) - { - if (parentColumns == null || parentColumns.Count == 0) - throw new ArgumentException($"{nameof(parentColumns)} is null or empty.", nameof(parentColumns)); + if (parentColumns == null || parentColumns.Count == 0) + throw new ArgumentException($"{nameof(parentColumns)} is null or empty.", nameof(parentColumns)); - if (childColumns == null || childColumns.Count == 0) - throw new ArgumentException($"{nameof(childColumns)} is null or empty.", nameof(childColumns)); + if (childColumns == null || childColumns.Count == 0) + throw new ArgumentException($"{nameof(childColumns)} is null or empty.", nameof(childColumns)); - ParentTableName = parentTableName; - ParentColumns = parentColumns; - ChildTableName = childTableName; - ChildColumns = childColumns; - } + ParentTableName = parentTableName; + ParentColumns = parentColumns; + ChildTableName = childTableName; + ChildColumns = childColumns; + } - /// - /// Gets the columns in the child table. - /// - public ColumnMetadataCollection ChildColumns { get; } + /// + /// Gets the columns in the child table. + /// + public ColumnMetadataCollection ChildColumns { get; } - /// - /// Gets the name of the child table. - /// - public string ChildTableName { get; } + /// + /// Gets the name of the child table. + /// + public string ChildTableName { get; } - /// - /// Gets the columns in the parent table. This will usually be the primary key(s). - /// - public ColumnMetadataCollection ParentColumns { get; } + /// + /// Gets the columns in the parent table. This will usually be the primary key(s). + /// + public ColumnMetadataCollection ParentColumns { get; } - /// - /// Gets the name of the parent table. - /// - public string ParentTableName { get; } - } + /// + /// Gets the name of the parent table. + /// + public string ParentTableName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection.cs index b6fdf3e55..849a26515 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection.cs @@ -1,42 +1,41 @@ using System.Collections; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// Class ForeignKeyConstraintCollection. +/// Implements the +/// +public class ForeignKeyConstraintCollection : IReadOnlyList { - /// Class ForeignKeyConstraintCollection. - /// Implements the - /// - public class ForeignKeyConstraintCollection : IReadOnlyList - { - readonly IReadOnlyList m_Source; + readonly IReadOnlyList m_Source; - /// - /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. - /// - /// The source. - internal ForeignKeyConstraintCollection(IReadOnlyList source) - { - m_Source = source; - } + /// + /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. + /// + /// The source. + internal ForeignKeyConstraintCollection(IReadOnlyList source) + { + m_Source = source; + } - /// Gets the number of elements in the collection. - /// The number of elements in the collection. - public int Count => m_Source.Count; + /// Gets the number of elements in the collection. + /// The number of elements in the collection. + public int Count => m_Source.Count; - /// Gets the element at the specified index in the read-only list. - /// The zero-based index of the element to get. - /// The element at the specified index in the read-only list. - public ForeignKeyConstraint this[int index] => m_Source[index]; + /// Gets the element at the specified index in the read-only list. + /// The zero-based index of the element to get. + /// The element at the specified index in the read-only list. + public ForeignKeyConstraint this[int index] => m_Source[index]; - /// Returns an enumerator that iterates through the collection. - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return m_Source.GetEnumerator(); - } + /// Returns an enumerator that iterates through the collection. + /// An enumerator that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + return m_Source.GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() - { - return m_Source.GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return m_Source.GetEnumerator(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection`2.cs index 639c66dd5..d6419faef 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraintCollection`2.cs @@ -1,26 +1,25 @@ using System.Collections.ObjectModel; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class ForeignKeyConstraintCollection. +/// +/// The type of the name. +/// The type of the database type. +public class ForeignKeyConstraintCollection : ReadOnlyCollection> + where TObjectName : struct + where TDbType : struct { - /// - /// Class ForeignKeyConstraintCollection. - /// - /// The type of the name. - /// The type of the database type. - public class ForeignKeyConstraintCollection : ReadOnlyCollection> - where TObjectName : struct - where TDbType : struct + /// Initializes a new instance of the class that is a read-only wrapper around the specified list. + /// The list to wrap. + public ForeignKeyConstraintCollection(IList> list) : base(list) { - /// Initializes a new instance of the class that is a read-only wrapper around the specified list. - /// The list to wrap. - public ForeignKeyConstraintCollection(IList> list) : base(list) - { - GenericCollection = new ForeignKeyConstraintCollection(this); - } - - /// - /// Gets the generic version of this collection. - /// - public ForeignKeyConstraintCollection GenericCollection { get; } + GenericCollection = new ForeignKeyConstraintCollection(this); } + + /// + /// Gets the generic version of this collection. + /// + public ForeignKeyConstraintCollection GenericCollection { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint`2.cs index 09cc80d96..e57a83c7f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ForeignKeyConstraint`2.cs @@ -1,53 +1,52 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This represents a foreign key relationship between two tables. +/// +/// The type of the name. +/// The database column type. +public class ForeignKeyConstraint : ForeignKeyConstraint + where TObjectName : struct + where TDbType : struct { /// - /// This represents a foreign key relationship between two tables. + /// Initializes a new instance of the class. /// - /// The type of the name. - /// The database column type. - public class ForeignKeyConstraint : ForeignKeyConstraint - where TObjectName : struct - where TDbType : struct + /// Name of the parent table. + /// The parent columns. + /// Name of the child table. + /// The child columns. + public ForeignKeyConstraint(TObjectName parentTableName, ColumnMetadataCollection parentColumns, TObjectName childTableName, ColumnMetadataCollection childColumns) : base(parentTableName.ToString()!, parentColumns?.GenericCollection!, childTableName.ToString()!, childColumns?.GenericCollection!) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the parent table. - /// The parent columns. - /// Name of the child table. - /// The child columns. - public ForeignKeyConstraint(TObjectName parentTableName, ColumnMetadataCollection parentColumns, TObjectName childTableName, ColumnMetadataCollection childColumns) : base(parentTableName.ToString()!, parentColumns?.GenericCollection!, childTableName.ToString()!, childColumns?.GenericCollection!) - { - if (parentColumns == null || parentColumns.Count == 0) - throw new ArgumentException($"{nameof(parentColumns)} is null or empty.", nameof(parentColumns)); + if (parentColumns == null || parentColumns.Count == 0) + throw new ArgumentException($"{nameof(parentColumns)} is null or empty.", nameof(parentColumns)); - if (childColumns == null || childColumns.Count == 0) - throw new ArgumentException($"{nameof(childColumns)} is null or empty.", nameof(childColumns)); + if (childColumns == null || childColumns.Count == 0) + throw new ArgumentException($"{nameof(childColumns)} is null or empty.", nameof(childColumns)); - ParentTableName = parentTableName; - ParentColumns = parentColumns; - ChildTableName = childTableName; - ChildColumns = childColumns; - } + ParentTableName = parentTableName; + ParentColumns = parentColumns; + ChildTableName = childTableName; + ChildColumns = childColumns; + } - /// - /// Gets the columns in the child table. - /// - public new ColumnMetadataCollection ChildColumns { get; } + /// + /// Gets the columns in the child table. + /// + public new ColumnMetadataCollection ChildColumns { get; } - /// - /// Gets the name of the child table. - /// - public new TObjectName ChildTableName { get; } + /// + /// Gets the name of the child table. + /// + public new TObjectName ChildTableName { get; } - /// - /// Gets the columns in the parent table. This will usually be the primary key(s). - /// - public new ColumnMetadataCollection ParentColumns { get; } + /// + /// Gets the columns in the parent table. This will usually be the primary key(s). + /// + public new ColumnMetadataCollection ParentColumns { get; } - /// - /// Gets the name of the parent table. - /// - public new TObjectName ParentTableName { get; } - } + /// + /// Gets the name of the parent table. + /// + public new TObjectName ParentTableName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/GenericDatabaseMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/GenericDatabaseMetadataCache.cs new file mode 100644 index 000000000..24a1210c0 --- /dev/null +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/GenericDatabaseMetadataCache.cs @@ -0,0 +1,99 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Tortuga.Chain.Metadata; + +/// +/// The GenericDatabaseMetadataCache cannot actually return metadata. It is only used for handling materializer type conversions. +/// Implements the +/// +/// +sealed class GenericDatabaseMetadataCache : IDatabaseMetadataCache +{ + const string NotSupportedMessage = "This data source does not expose database metadata."; + + /// + /// Gets the converter dictionary used by materializers. + /// + /// The converter dictionary. + public MaterializerTypeConverter Converter { get; } = new(); + + int? IDatabaseMetadataCache.MaxParameters => null; + + StoredProcedureMetadata IDatabaseMetadataCache.GetStoredProcedure(string procedureName) + { + throw new NotImplementedException(NotSupportedMessage); + } + + IReadOnlyCollection IDatabaseMetadataCache.GetStoredProcedures() + { + throw new NotImplementedException(NotSupportedMessage); + } + + TableFunctionMetadata IDatabaseMetadataCache.GetTableFunction(string tableFunctionName) + { + throw new NotImplementedException(NotSupportedMessage); + } + + IReadOnlyCollection IDatabaseMetadataCache.GetTableFunctions() + { + throw new NotImplementedException(NotSupportedMessage); + } + + TableOrViewMetadata IDatabaseMetadataCache.GetTableOrView(string tableName) + { + throw new NotImplementedException(NotSupportedMessage); + } + + TableOrViewMetadata IDatabaseMetadataCache.GetTableOrViewFromClass(OperationType operation) + { + throw new NotImplementedException(NotSupportedMessage); + } + + TableOrViewMetadata IDatabaseMetadataCache.GetTableOrViewFromClass(Type type, OperationType operation) + { + throw new NotImplementedException(NotSupportedMessage); + } + + IReadOnlyCollection IDatabaseMetadataCache.GetTablesAndViews() + { + throw new NotImplementedException(NotSupportedMessage); + } + + UserDefinedTableTypeMetadata IDatabaseMetadataCache.GetUserDefinedTableType(string typeName) + { + throw new NotImplementedException(NotSupportedMessage); + } + + IReadOnlyCollection IDatabaseMetadataCache.GetUserDefinedTableTypes() + { + throw new NotImplementedException(NotSupportedMessage); + } + + void IDatabaseMetadataCache.Preload() + { + } + + void IDatabaseMetadataCache.Reset() + { + } + + bool IDatabaseMetadataCache.TryGetStoredProcedure(string procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure) + { + throw new NotImplementedException(NotSupportedMessage); + } + + bool IDatabaseMetadataCache.TryGetTableFunction(string tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction) + { + throw new NotImplementedException(NotSupportedMessage); + } + + bool IDatabaseMetadataCache.TryGetTableOrView(string tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView) + { + throw new NotImplementedException(NotSupportedMessage); + } + + bool IDatabaseMetadataCache.TryGetUserDefinedTableType(string typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType) + { + throw new NotImplementedException(NotSupportedMessage); + } +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IDatabaseMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IDatabaseMetadataCache.cs index afeb41bcc..5c407dbf8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IDatabaseMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IDatabaseMetadataCache.cs @@ -1,147 +1,150 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Abstract version of the database metadata cache. +/// +public interface IDatabaseMetadataCache { /// - /// Abstract version of the database metadata cache. - /// - public interface IDatabaseMetadataCache - { - /// - /// Gets the stored procedure's metadata. - /// - /// Name of the procedure. - /// - StoredProcedureMetadata GetStoredProcedure(string procedureName); - - /// - /// Gets the stored procedures that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - IReadOnlyCollection GetStoredProcedures(); - - /// - /// Gets the metadata for a table function. - /// - /// Name of the table function. - TableFunctionMetadata GetTableFunction(string tableFunctionName); - - /// - /// Gets the table-valued functions that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - IReadOnlyCollection GetTableFunctions(); - - /// - /// Gets the metadata for a table or view. - /// - /// Name of the table or view. - /// - TableOrViewMetadata GetTableOrView(string tableName); - - - /// - /// Returns the table or view derived from the class's name and/or Table attribute. - /// - /// - /// - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - TableOrViewMetadata GetTableOrViewFromClass(OperationType operation = OperationType.All); - - - /// - /// Returns the table or view derived from the class's name and/or Table attribute. - /// - /// - /// - /// - TableOrViewMetadata GetTableOrViewFromClass(Type type, OperationType operation = OperationType.All); - - /// - /// Gets the tables and views that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - IReadOnlyCollection GetTablesAndViews(); - - /// - /// Gets the metadata for a user defined type. - /// - /// Name of the type. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - UserDefinedTableTypeMetadata GetUserDefinedTableType(string typeName); - - /// - /// Gets the user defined table types that were loaded by this cache. - /// - /// - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - IReadOnlyCollection GetUserDefinedTableTypes(); - - /// - /// Preloads all of the metadata for this data source. - /// - void Preload(); - - ///// - ///// Preloads all of the tables for this data source. - ///// - //void PreloadTables(); - - ///// - ///// Preloads all of the views for this data source. - ///// - //void PreloadViews(); - - /// - /// Resets the metadata cache, clearing out all cached metadata. - /// - void Reset(); - - /// - /// Tries to get the stored procedure's metadata. - /// - /// Name of the procedure. - /// The stored procedure. - /// - bool TryGetStoredProcedure(string procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure); - - /// - /// Tries to get the metadata for a table function. - /// - /// Name of the table function. - /// The table function. - /// - bool TryGetTableFunction(string tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction); - - /// - /// Tries to get the metadata for a table or view. - /// - /// Name of the table or view. - /// The table or view. - /// - bool TryGetTableOrView(string tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView); - - /// - /// Try to get the metadata for a user defined type. - /// - /// Name of the type. - /// Type of the user defined table type. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - bool TryGetUserDefinedTableType(string typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType); - - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - int? MaxParameters { get; } - } + /// Gets the converter dictionary used by materializers. + /// + /// The converter dictionary. + MaterializerTypeConverter Converter { get; } + + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + int? MaxParameters { get; } + + /// + /// Gets the stored procedure's metadata. + /// + /// Name of the procedure. + /// + StoredProcedureMetadata GetStoredProcedure(string procedureName); + + /// + /// Gets the stored procedures that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + IReadOnlyCollection GetStoredProcedures(); + + /// + /// Gets the metadata for a table function. + /// + /// Name of the table function. + TableFunctionMetadata GetTableFunction(string tableFunctionName); + + /// + /// Gets the table-valued functions that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + IReadOnlyCollection GetTableFunctions(); + + /// + /// Gets the metadata for a table or view. + /// + /// Name of the table or view. + /// + TableOrViewMetadata GetTableOrView(string tableName); + + /// + /// Returns the table or view derived from the class's name and/or Table attribute. + /// + /// + /// + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + TableOrViewMetadata GetTableOrViewFromClass(OperationType operation = OperationType.All); + + /// + /// Returns the table or view derived from the class's name and/or Table attribute. + /// + /// + /// + /// + TableOrViewMetadata GetTableOrViewFromClass(Type type, OperationType operation = OperationType.All); + + /// + /// Gets the tables and views that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + IReadOnlyCollection GetTablesAndViews(); + + /// + /// Gets the metadata for a user defined type. + /// + /// Name of the type. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + UserDefinedTableTypeMetadata GetUserDefinedTableType(string typeName); + + /// + /// Gets the user defined table types that were loaded by this cache. + /// + /// + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + IReadOnlyCollection GetUserDefinedTableTypes(); + + /// + /// Preloads all of the metadata for this data source. + /// + void Preload(); + + ///// + ///// Preloads all of the tables for this data source. + ///// + //void PreloadTables(); + + ///// + ///// Preloads all of the views for this data source. + ///// + //void PreloadViews(); + + /// + /// Resets the metadata cache, clearing out all cached metadata. + /// + void Reset(); + + /// + /// Tries to get the stored procedure's metadata. + /// + /// Name of the procedure. + /// The stored procedure. + /// + bool TryGetStoredProcedure(string procedureName, [NotNullWhen(true)] out StoredProcedureMetadata? storedProcedure); + + /// + /// Tries to get the metadata for a table function. + /// + /// Name of the table function. + /// The table function. + /// + bool TryGetTableFunction(string tableFunctionName, [NotNullWhen(true)] out TableFunctionMetadata? tableFunction); + + /// + /// Tries to get the metadata for a table or view. + /// + /// Name of the table or view. + /// The table or view. + /// + bool TryGetTableOrView(string tableName, [NotNullWhen(true)] out TableOrViewMetadata? tableOrView); + + /// + /// Try to get the metadata for a user defined type. + /// + /// Name of the type. + /// Type of the user defined table type. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + bool TryGetUserDefinedTableType(string typeName, [NotNullWhen(true)] out UserDefinedTableTypeMetadata? userDefinedTableType); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails.cs index d75d42447..24ba946c9 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails.cs @@ -1,75 +1,74 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This interface is used to allow SqlBuilder to be used with stored procs, TVFs, and other non-table objects. +/// +/// +/// For internal use only. +public interface ISqlBuilderEntryDetails { /// - /// This interface is used to allow SqlBuilder to be used with stored procs, TVFs, and other non-table objects. + /// Gets the name of the color. /// - /// - /// For internal use only. - public interface ISqlBuilderEntryDetails - { - /// - /// Gets the name of the color. - /// - /// The name of the color. - string ClrName { get; } + /// The name of the color. + string ClrName { get; } - /// - /// Gets or sets the full name of the type including max length, precision, and/or scale. - /// - /// - /// The full name of the type. - /// - string FullTypeName { get; } + /// + /// Indicates the direction of the parameter. + /// + ParameterDirection Direction { get; } - /// - /// Gets a value indicating whether this instance is identity. - /// - /// true if this instance is identity; otherwise, false. - bool IsIdentity { get; } + /// + /// Gets or sets the full name of the type including max length, precision, and/or scale. + /// + /// + /// The full name of the type. + /// + string FullTypeName { get; } - /// - /// Gets the name of the quoted SQL. - /// - /// The name of the quoted SQL. - string? QuotedSqlName { get; } + /// + /// Gets a value indicating whether this instance is identity. + /// + /// true if this instance is identity; otherwise, false. + bool IsIdentity { get; } - /// - /// Gets or sets the scale. - /// - /// - /// The scale. - /// - int? Scale { get; } + /// + /// Gets the maximum length. + /// + /// + /// The maximum length. + /// + int? MaxLength { get; } - /// - /// Gets the name of the SQL. - /// - /// The name of the SQL. - string? SqlName { get; } + /// + /// Gets the name of the quoted SQL. + /// + /// The name of the quoted SQL. + string? QuotedSqlName { get; } - /// - /// Gets the name of the SQL variable. - /// - /// The name of the SQL variable. - string SqlVariableName { get; } + /// + /// Gets or sets the scale. + /// + /// + /// The scale. + /// + int? Scale { get; } - /// - /// Gets the name of the type. - /// - /// The name of the type. - string TypeName { get; } + /// + /// Gets the name of the SQL. + /// + /// The name of the SQL. + string? SqlName { get; } - /// - /// Indicates the direction of the parameter. - /// - ParameterDirection Direction { get; } + /// + /// Gets the name of the SQL variable. + /// + /// The name of the SQL variable. + string SqlVariableName { get; } - /// - /// Gets the maximum length. - /// - /// - /// The maximum length. - /// - int? MaxLength { get; } - } + /// + /// Gets the name of the type. + /// + /// The name of the type. + string TypeName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails`1.cs index a54b003ef..5aace9d6d 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ISqlBuilderEntryDetails`1.cs @@ -1,16 +1,15 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This interface is used to allow SqlBuilder to be used with stored procs, TVFs, and other non-table objects. +/// +/// The type of the database type. +/// For internal use only. +public interface ISqlBuilderEntryDetails : ISqlBuilderEntryDetails where TDbType : struct { /// - /// This interface is used to allow SqlBuilder to be used with stored procs, TVFs, and other non-table objects. + /// Gets the database specific DbType /// - /// The type of the database type. - /// For internal use only. - public interface ISqlBuilderEntryDetails : ISqlBuilderEntryDetails where TDbType : struct - { - /// - /// Gets the database specific DbType - /// - /// The type of the database. - TDbType? DbType { get; } - } + /// The type of the database. + TDbType? DbType { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata.cs index 6eb4329c6..1e74589c5 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata.cs @@ -1,38 +1,37 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// Class IndexColumnMetadata. +public abstract class IndexColumnMetadata { - /// Class IndexColumnMetadata. - public abstract class IndexColumnMetadata + /// Initializes a new instance of the IndexColumnMetadata class. + /// The underlying column details. + /// Indicates the column is indexed in descending order. + /// Indicates the column is an unindexed, included column. + protected IndexColumnMetadata(ColumnMetadata column, bool? isDescending, bool isIncluded) { - /// Initializes a new instance of the IndexColumnMetadata class. - /// The underlying column details. - /// Indicates the column is indexed in descending order. - /// Indicates the column is an unindexed, included column. - protected IndexColumnMetadata(ColumnMetadata column, bool? isDescending, bool isIncluded) - { - Details = column; - IsDescending = isDescending; - IsIncluded = isIncluded; - } + Details = column; + IsDescending = isDescending; + IsIncluded = isIncluded; + } - /// - /// Gets the underlying column. - /// - public ColumnMetadata Details { get; } + /// + /// Gets the underlying column. + /// + public ColumnMetadata Details { get; } - /// - /// Gets a value indicating whether this instance is descending. - /// - /// This should be null for included columns. - public bool? IsDescending { get; } + /// + /// Gets a value indicating whether this instance is descending. + /// + /// This should be null for included columns. + public bool? IsDescending { get; } - /// - /// Gets a value indicating whether this instance is an included column. - /// - public bool IsIncluded { get; } + /// + /// Gets a value indicating whether this instance is an included column. + /// + public bool IsIncluded { get; } - /// - /// Gets the name used by the database. - /// - public string SqlName => Details.SqlName; - } + /// + /// Gets the name used by the database. + /// + public string SqlName => Details.SqlName; } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection.cs index 0626ff26b..ba8933e58 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection.cs @@ -1,59 +1,58 @@ using System.Collections; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class IndexColumnMetadataCollection. +/// Implements the +/// +/// +public class IndexColumnMetadataCollection : IReadOnlyList { + readonly IReadOnlyList m_Source; + /// - /// Class IndexColumnMetadataCollection. - /// Implements the + /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. /// - /// - public class IndexColumnMetadataCollection : IReadOnlyList + /// The source. + internal IndexColumnMetadataCollection(IReadOnlyList source) + { + m_Source = source; + } + + /// Gets the number of elements in the collection. + /// The number of elements in the collection. + public int Count => m_Source.Count; + + /// Gets the element at the specified index in the read-only list. + /// The zero-based index of the element to get. + /// The element at the specified index in the read-only list. + public IndexColumnMetadata this[int index] => m_Source[index]; + + /// Returns an enumerator that iterates through the collection. + /// An enumerator that can be used to iterate through the collection. + public IEnumerator GetEnumerator() { - readonly IReadOnlyList m_Source; - - /// - /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. - /// - /// The source. - internal IndexColumnMetadataCollection(IReadOnlyList source) - { - m_Source = source; - } - - /// Gets the number of elements in the collection. - /// The number of elements in the collection. - public int Count => m_Source.Count; - - /// Gets the element at the specified index in the read-only list. - /// The zero-based index of the element to get. - /// The element at the specified index in the read-only list. - public IndexColumnMetadata this[int index] => m_Source[index]; - - /// Returns an enumerator that iterates through the collection. - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return m_Source.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return m_Source.GetEnumerator(); - } - - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// If the column name was not found, this will return null - public IndexColumnMetadata? TryGetColumn(string columnName) - { - foreach (var item in this) - if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) - return item; - - return null; - } + return m_Source.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_Source.GetEnumerator(); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// If the column name was not found, this will return null + public IndexColumnMetadata? TryGetColumn(string columnName) + { + foreach (var item in this) + if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) + return item; + + return null; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection`1.cs index 9e2aa59c9..15c29e3af 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadataCollection`1.cs @@ -1,40 +1,39 @@ using System.Collections.ObjectModel; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// Class IndexColumnMetadataCollection. +/// The database column type. +public class IndexColumnMetadataCollection : ReadOnlyCollection> + where TDbType : struct { - /// Class IndexColumnMetadataCollection. - /// The database column type. - public class IndexColumnMetadataCollection : ReadOnlyCollection> - where TDbType : struct + /// + /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. + /// + /// The source. + public IndexColumnMetadataCollection(IEnumerable> source) : base(source.ToList()) { - /// - /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. - /// - /// The source. - public IndexColumnMetadataCollection(IEnumerable> source) : base(source.ToList()) - { - GenericCollection = new IndexColumnMetadataCollection(this); - } + GenericCollection = new IndexColumnMetadataCollection(this); + } - /// - /// Gets the generic version of this collection. - /// - /// We can't make this implement IReadOnlyList because it breaks LINQ. - public IndexColumnMetadataCollection GenericCollection { get; } + /// + /// Gets the generic version of this collection. + /// + /// We can't make this implement IReadOnlyList because it breaks LINQ. + public IndexColumnMetadataCollection GenericCollection { get; } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// If the column name was not found, this will return null - public IndexColumnMetadata? TryGetColumn(string columnName) - { - foreach (var item in this) - if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) - return item; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// If the column name was not found, this will return null + public IndexColumnMetadata? TryGetColumn(string columnName) + { + foreach (var item in this) + if (item.SqlName.Equals(columnName, System.StringComparison.OrdinalIgnoreCase)) + return item; - return null; - } + return null; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata`1.cs index 3a3a71b44..ee05e4ed5 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexColumnMetadata`1.cs @@ -1,26 +1,25 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// Class IndexColumnMetadata. +/// Implements the +/// The type of the t database type. +/// +public class IndexColumnMetadata : IndexColumnMetadata + where TDbType : struct { - /// Class IndexColumnMetadata. - /// Implements the - /// The type of the t database type. - /// - public class IndexColumnMetadata : IndexColumnMetadata - where TDbType : struct + /// + /// Initializes a new instance of the IndexColumnMetadata class. + /// + /// The underlying column details. + /// Indicates the column is indexed in descending order. + /// Indicates the column is an unindexed, included column. + public IndexColumnMetadata(ColumnMetadata column, bool? isDescending, bool isIncluded) : base(column, isDescending, isIncluded) { - /// - /// Initializes a new instance of the IndexColumnMetadata class. - /// - /// The underlying column details. - /// Indicates the column is indexed in descending order. - /// Indicates the column is an unindexed, included column. - public IndexColumnMetadata(ColumnMetadata column, bool? isDescending, bool isIncluded) : base(column, isDescending, isIncluded) - { - Details = column; - } - - /// - /// Gets the underlying column. - /// - public new ColumnMetadata Details { get; } + Details = column; } + + /// + /// Gets the underlying column. + /// + public new ColumnMetadata Details { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata.cs index d4ed625ee..1ad62d2b8 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata.cs @@ -1,90 +1,89 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for an index. +/// +public abstract class IndexMetadata { - /// - /// Metadata for an index. - /// - public abstract class IndexMetadata + /// Initializes a new instance of the class. + /// Name of the table (or view). + /// The name. + /// if set to true is a primary key. + /// if set to true is a unique index. + /// if set to true is a unique constraint. + /// The columns. + /// Approximate index size in KB + /// Approximate row count + /// Type of the index. + protected IndexMetadata(string tableName, string? name, bool isPrimaryKey, bool isUnique, bool isUniqueConstraint, IndexColumnMetadataCollection columns, long? indexSizeKB, long? rowCount, IndexType indexType) { - /// Initializes a new instance of the class. - /// Name of the table (or view). - /// The name. - /// if set to true is a primary key. - /// if set to true is a unique index. - /// if set to true is a unique constraint. - /// The columns. - /// Approximate index size in KB - /// Approximate row count - /// Type of the index. - protected IndexMetadata(string tableName, string? name, bool isPrimaryKey, bool isUnique, bool isUniqueConstraint, IndexColumnMetadataCollection columns, long? indexSizeKB, long? rowCount, IndexType indexType) - { - TableName = tableName; - Name = name; - IsUnique = isUnique; - IsUniqueConstraint = isUniqueConstraint; - IsPrimaryKey = isPrimaryKey; - Columns = columns; - IndexSizeKB = indexSizeKB; - RowCount = rowCount; - IndexType = indexType; - } + TableName = tableName; + Name = name; + IsUnique = isUnique; + IsUniqueConstraint = isUniqueConstraint; + IsPrimaryKey = isPrimaryKey; + Columns = columns; + IndexSizeKB = indexSizeKB; + RowCount = rowCount; + IndexType = indexType; + } - /// - /// Gets the columns. - /// - public IndexColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + public IndexColumnMetadataCollection Columns { get; } - /// - /// Gets the approximate index size in kilobytes. - /// - public long? IndexSizeKB { get; } + /// + /// Gets the approximate index size in kilobytes. + /// + public long? IndexSizeKB { get; } - /// Gets the type of the index. - public IndexType IndexType { get; } + /// Gets the type of the index. + public IndexType IndexType { get; } - /// - /// Gets a value indicating whether this index is a primary key. - /// - /// - /// true if this instance is primary key; otherwise, false. - /// - public bool IsPrimaryKey { get; } + /// + /// Gets a value indicating whether this index is a primary key. + /// + /// + /// true if this instance is primary key; otherwise, false. + /// + public bool IsPrimaryKey { get; } - /// - /// Gets a value indicating whether this is a unique index. - /// - /// - /// true if this instance is unique; otherwise, false. - /// - public bool IsUnique { get; } + /// + /// Gets a value indicating whether this is a unique index. + /// + /// + /// true if this instance is unique; otherwise, false. + /// + public bool IsUnique { get; } - /// - /// Gets a value indicating whether this is a unique constraint. - /// - /// - /// true if this instance is unique; otherwise, false. - /// - /// In some database, a unique index is not necessary a unique constraint. - public bool IsUniqueConstraint { get; } + /// + /// Gets a value indicating whether this is a unique constraint. + /// + /// + /// true if this instance is unique; otherwise, false. + /// + /// In some database, a unique index is not necessary a unique constraint. + public bool IsUniqueConstraint { get; } - /// - /// Gets the name of the index. - /// - /// - /// The name. - /// - public string? Name { get; } + /// + /// Gets the name of the index. + /// + /// + /// The name. + /// + public string? Name { get; } - /// - /// Gets the approximate row count. - /// - public long? RowCount { get; } + /// + /// Gets the approximate row count. + /// + public long? RowCount { get; } - /// - /// Gets the name of the table (or view) the index applies to. - /// - /// - /// The name of the table. - /// - public string TableName { get; } - } + /// + /// Gets the name of the table (or view) the index applies to. + /// + /// + /// The name of the table. + /// + public string TableName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection.cs index ae2b6934e..62f3ae045 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection.cs @@ -1,50 +1,49 @@ using System.Collections; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class IndexMetadataCollection. +/// +public class IndexMetadataCollection : IReadOnlyList { - /// - /// Class IndexMetadataCollection. - /// - public class IndexMetadataCollection : IReadOnlyList - { - readonly IReadOnlyList m_Source; + readonly IReadOnlyList m_Source; - /// Initializes a new instance of the class. - /// The source. - public IndexMetadataCollection(IReadOnlyList source) - { - m_Source = source; - } + /// Initializes a new instance of the class. + /// The source. + public IndexMetadataCollection(IReadOnlyList source) + { + m_Source = source; + } - /// - /// Gets the number of elements in the collection. - /// - public int Count => m_Source.Count; + /// + /// Gets the number of elements in the collection. + /// + public int Count => m_Source.Count; - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// - public IndexMetadata this[int index] => m_Source[index]; + /// + /// Gets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// + public IndexMetadata this[int index] => m_Source[index]; - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return m_Source.GetEnumerator(); - } + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return m_Source.GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() - { - return m_Source.GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return m_Source.GetEnumerator(); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection`2.cs index a12d954d0..0119861b5 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadataCollection`2.cs @@ -1,21 +1,20 @@ using System.Collections.ObjectModel; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// Class IndexMetadataCollection. +/// +/// The type of the name. +/// The database column type. +public class IndexMetadataCollection : ReadOnlyCollection> + where TObjectName : struct + where TDbType : struct { - /// Class IndexMetadataCollection. - /// - /// The type of the name. - /// The database column type. - public class IndexMetadataCollection : ReadOnlyCollection> - where TObjectName : struct - where TDbType : struct + /// + /// Initializes a new instance of the class. + /// + /// The list to wrap. + public IndexMetadataCollection(IList> list) : base(list) { - /// - /// Initializes a new instance of the class. - /// - /// The list to wrap. - public IndexMetadataCollection(IList> list) : base(list) - { - } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata`1.cs index 7196e1205..d6e052927 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexMetadata`1.cs @@ -1,43 +1,42 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for an index. +/// +/// The type of the name. +/// The database column type. +/// +public class IndexMetadata : IndexMetadata + where TObjectName : struct + where TDbType : struct { - /// - /// Metadata for an index. - /// - /// The type of the name. - /// The database column type. - /// - public class IndexMetadata : IndexMetadata - where TObjectName : struct - where TDbType : struct + /// Initializes a new instance of the class. + /// Name of the table (or view). + /// The name. + /// if set to true is a primary key. + /// if set to true is a unique index. + /// if set to true is a unique constraint. + /// The columns. + /// Approximate index size in KB + /// Approximate row count + /// Type of the index. + /// columns + public IndexMetadata(TObjectName tableName, string? name, bool isPrimaryKey, bool isUnique, bool isUniqueConstraint, IndexColumnMetadataCollection columns, long? indexSizeKB, long? rowCount, IndexType indexType) : base(tableName.ToString()!, name, isPrimaryKey, isUnique, isUniqueConstraint, columns?.GenericCollection!, indexSizeKB, rowCount, indexType) { - /// Initializes a new instance of the class. - /// Name of the table (or view). - /// The name. - /// if set to true is a primary key. - /// if set to true is a unique index. - /// if set to true is a unique constraint. - /// The columns. - /// Approximate index size in KB - /// Approximate row count - /// Type of the index. - /// columns - public IndexMetadata(TObjectName tableName, string? name, bool isPrimaryKey, bool isUnique, bool isUniqueConstraint, IndexColumnMetadataCollection columns, long? indexSizeKB, long? rowCount, IndexType indexType) : base(tableName.ToString()!, name, isPrimaryKey, isUnique, isUniqueConstraint, columns?.GenericCollection!, indexSizeKB, rowCount, indexType) - { - TableName = tableName; - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - } + TableName = tableName; + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + } - /// - /// Gets the columns. - /// - public new IndexColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + public new IndexColumnMetadataCollection Columns { get; } - /// - /// Gets the name of the table (or view) the index applies to. - /// - /// - /// The name of the table. - /// - public new TObjectName TableName { get; } - } + /// + /// Gets the name of the table (or view) the index applies to. + /// + /// + /// The name of the table. + /// + public new TObjectName TableName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexType.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexType.cs index 5fc9359c6..d3e0b564f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexType.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/IndexType.cs @@ -1,97 +1,96 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Enum IndexType +/// +public enum IndexType { /// - /// Enum IndexType - /// - public enum IndexType - { - /// - /// Unknown index type. - /// - Unknown = 0, - - /// - /// B-Tree Index - /// - BTree = 1, - - /// - /// Hash - /// - Hash = 2, - - /// - /// Generalized Inverted Search Tree (GiST) - /// - Gist = 3, - - /// - /// Generalized Inverted Index (GIN) - /// - Gin = 4, - - /// - /// Space partitioned GiST (SP-GiST) - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Spgist")] - Spgist = 5, - - /// - /// Block Range Indexes (BRIN) - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Brin")] - Brin = 6, - - /// - /// R-Tree Index - /// - RTree = 7, - - /// - /// Full Text Index - /// - FullText = 8, - - /// - /// Heap - /// - Heap = 9, - - /// - /// Clustered - /// - Clustered = 10, - - /// - /// Nonclustered - /// - Nonclustered = 11, - - /// - /// XML - /// - Xml = 12, - - /// - /// Spatial - /// - Spatial = 13, - - /// - /// Clustered columnstore index - /// - ClusteredColumnstoreIndex = 14, - - /// - /// Nonclustered columnstore index - /// - NonclusteredColumnstoreIndex = 15, - - /// - /// Nonclustered hash index - /// - NonclusteredHashIndex = 16 - } + /// Unknown index type. + /// + Unknown = 0, + + /// + /// B-Tree Index + /// + BTree = 1, + + /// + /// Hash + /// + Hash = 2, + + /// + /// Generalized Inverted Search Tree (GiST) + /// + Gist = 3, + + /// + /// Generalized Inverted Index (GIN) + /// + Gin = 4, + + /// + /// Space partitioned GiST (SP-GiST) + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Spgist")] + Spgist = 5, + + /// + /// Block Range Indexes (BRIN) + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Brin")] + Brin = 6, + + /// + /// R-Tree Index + /// + RTree = 7, + + /// + /// Full Text Index + /// + FullText = 8, + + /// + /// Heap + /// + Heap = 9, + + /// + /// Clustered + /// + Clustered = 10, + + /// + /// Nonclustered + /// + Nonclustered = 11, + + /// + /// XML + /// + Xml = 12, + + /// + /// Spatial + /// + Spatial = 13, + + /// + /// Clustered columnstore index + /// + ClusteredColumnstoreIndex = 14, + + /// + /// Nonclustered columnstore index + /// + NonclusteredColumnstoreIndex = 15, + + /// + /// Nonclustered hash index + /// + NonclusteredHashIndex = 16 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/MaterializerTypeConverter.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/MaterializerTypeConverter.cs new file mode 100644 index 000000000..3b9a8184c --- /dev/null +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/MaterializerTypeConverter.cs @@ -0,0 +1,206 @@ +using System.Collections.Concurrent; +using System.Globalization; +using System.Reflection; +using System.Xml.Linq; + +namespace Tortuga.Chain.Metadata; + +/// +/// MaterializerTypeConverterDictionary is used when a type conversion is needed while materializing an object. +/// +public class MaterializerTypeConverter +{ + bool m_HasCustomerConverters; + private readonly ConcurrentDictionary<(Type input, Type output), Func> m_ConverterDictionary = new(); + + /// + /// Initializes an instance of the class with the default set of converters. + /// + public MaterializerTypeConverter() + { + } + + /// + /// Adds the converter to by used by materializers. + /// + /// The original type of the value + /// The desired type of the value. + /// The converter function. + /// converter + public void AddConverter(Func converter) + { + if (converter == null) + throw new ArgumentNullException(nameof(converter), $"{nameof(converter)} is null."); + + var typeKey = (typeof(TIn), typeof(TOut)); + m_ConverterDictionary[typeKey] = (input) => converter((TIn)input)!; + + m_HasCustomerConverters = true; + //Future versions may capture the Func version of the converter as well. + //For now we're just using this pattern to ensure that TIn/TOut match the real effect of the Func converter function. + } + + /// + /// Tries the convert the value into the indicated type. + /// + /// Desired type + /// The value to be converted. + /// If an exception occurs when converting, it will be returned here. + /// true if the conversion was successful, false otherwise. + public bool TryConvertType(Type targetType, ref object? value, out Exception? conversionException) + { + conversionException = null; + + if (value == null) + return true; + + if (value is DBNull) + { + value = null; + return true; + } + + var targetTypeInfo = targetType.GetTypeInfo(); + + //For Nullable, we only care about the type parameter + if (targetType.Name == "Nullable`1" && targetTypeInfo.IsGenericType) + { + //isNullable = true; + targetType = targetType.GenericTypeArguments[0]; + targetTypeInfo = targetType.GetTypeInfo(); + } + + try + { + //Check the converter map + if (m_HasCustomerConverters && m_ConverterDictionary.TryGetValue((value.GetType(), targetType), out var converter)) + { + value = converter(value); + return true; + } + + //some database return strings when we want strong types + if (value is string) + { + if (targetType == typeof(XElement)) + { + value = XElement.Parse((string)value); + return true; + } + else if (targetType == typeof(XDocument)) + { + value = XDocument.Parse((string)value); + return true; + } + else if (targetTypeInfo.IsEnum) + { + value = Enum.Parse(targetType, (string)value); + return true; + } + else if (targetType == typeof(bool)) + { + value = bool.Parse((string)value); + return true; + } + else if (targetType == typeof(short)) + { + value = short.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(int)) + { + value = int.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(long)) + { + value = long.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(float)) + { + value = float.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(double)) + { + value = double.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(decimal)) + { + value = decimal.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(DateTime)) + { + value = DateTime.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(DateTimeOffset)) + { + value = DateTimeOffset.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } + else if (targetType == typeof(TimeSpan)) + { + value = TimeSpan.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } +#if NET6_0_OR_GREATER + else if (targetType == typeof(TimeOnly)) + { + value = TimeOnly.Parse((string)value, CultureInfo.InvariantCulture); + return true; + } +#endif + + return false; + } + + if (targetTypeInfo.IsEnum) + value = Enum.ToObject(targetType, value); + + if (value is DateTime dt) + { +#if NET6_0_OR_GREATER + if (targetType == typeof(DateOnly)) + { + value = DateOnly.FromDateTime(dt); + return true; + } + if (targetType == typeof(TimeOnly)) + { + value = TimeOnly.FromDateTime(dt); + return true; + } +#endif + if (targetType == typeof(TimeSpan)) + { + value = dt.TimeOfDay; + return true; + } + } + + if (value is TimeSpan ts) + { +#if NET6_0_OR_GREATER + if (targetType == typeof(TimeOnly)) + { + value = TimeOnly.FromTimeSpan(ts); + return true; + } +#endif + } + + //this will handle numeric conversions + value = Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture); + return true; + } + catch (Exception ex) + { + conversionException = ex; + return false; + } + } +} diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/NameGenerationOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/NameGenerationOptions.cs index 73309e834..08a724b17 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/NameGenerationOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/NameGenerationOptions.cs @@ -1,32 +1,32 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Language options needed for code generation scenarios. +/// +[Flags] +public enum NameGenerationOptions { /// - /// Language options needed for code generation scenarios. + /// No options /// - [Flags] - public enum NameGenerationOptions - { - /// - /// No options - /// - None = 0, + None = 0, - /// - /// Use C# type names - /// - CSharp = 1, + /// + /// Use C# type names + /// + CSharp = 1, - /// - /// Use Visual Basic type names - /// - VisualBasic = 2, + /// + /// Use Visual Basic type names + /// + VisualBasic = 2, - /// - /// Use F# type names - /// - FSharp = 4, + /// + /// Use F# type names + /// + FSharp = 4, - /* + /* /// /// Use short names instead of fully qualified names. When possible, language specific names will be used (e.g. int vs System.Int32). @@ -35,26 +35,25 @@ public enum NameGenerationOptions */ - /// - /// If the column's nullability is unknown, assume that it is nullable. - /// - AssumeNullable = 16, - - /// - /// Use the nullable reference types option from C# 8. - /// - NullableReferenceTypes = 32, - - /// - /// Treat the type as nullable even if the column/parameter isn't nullable. - /// - /// This is for database generated values such as identity and created date columns - ForceNullable = 64, - - /// - /// Treat the type as non-nullable even if the column/parameter isn't nullable. - /// - /// This is needed for legacy serializers that don't support nullable primitives. - ForceNonNullable = 128 - } + /// + /// If the column's nullability is unknown, assume that it is nullable. + /// + AssumeNullable = 16, + + /// + /// Use the nullable reference types option from C# 8. + /// + NullableReferenceTypes = 32, + + /// + /// Treat the type as nullable even if the column/parameter isn't nullable. + /// + /// This is for database generated values such as identity and created date columns + ForceNullable = 64, + + /// + /// Treat the type as non-nullable even if the column/parameter isn't nullable. + /// + /// This is needed for legacy serializers that don't support nullable primitives. + ForceNonNullable = 128 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/OperationTypes.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/OperationTypes.cs index 752502327..4921b5d80 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/OperationTypes.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/OperationTypes.cs @@ -1,17 +1,17 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Indicates the type of operation being performed. +/// +/// Keep numbers in sync with AuditRules.OperationTypes. +public enum OperationType { /// - /// Indicates the type of operation being performed. + /// Undefined operation, return the default table. /// - /// Keep numbers in sync with AuditRules.OperationTypes. - public enum OperationType - { - /// - /// Undefined operation, return the default table. - /// - All = 0, + All = 0, - /* TASK-350: Reserved for future work + /* TASK-350: Reserved for future work /// /// The table, function, or stored procedure used for insert operations. /// @@ -28,9 +28,8 @@ public enum OperationType Delete = 4, */ - /// - /// The table or view select operations. - /// - Select = 8, - } + /// + /// The table or view select operations. + /// + Select = 8, } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata.cs index d89f41ab7..4c69bf8cd 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata.cs @@ -1,132 +1,113 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for a stored procedure parameter +/// +public abstract class ParameterMetadata : ISqlBuilderEntryDetails { /// - /// Metadata for a stored procedure parameter + /// Initializes a new instance of the class. /// - public abstract class ParameterMetadata : ISqlBuilderEntryDetails + /// Name of the SQL parameter. + /// Name of the SQL variable. + /// Name of the type as known to the database. + /// Type of the database column as an enum. + /// if set to true is nullable. + /// The maximum length. + /// The precision. + /// The scale. + /// Full name of the type. + /// Indicates the direction of the parameter. + protected ParameterMetadata(string sqlParameterName, string sqlVariableName, string typeName, object? dbType, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, ParameterDirection direction) { - /* - /// - /// Initializes a new instance of the class. - /// - /// Name of the SQL parameter. - /// Name of the SQL variable. - /// Name of the type as known to the database. - /// Type of the database column as an enum. - protected ParameterMetadata(string sqlParameterName, string sqlVariableName, string typeName, object dbType) - { - TypeName = typeName; - SqlParameterName = sqlParameterName; - ClrName = Utilities.ToClrName(sqlParameterName); - SqlVariableName = sqlVariableName; - DbType = dbType; - } - */ - - /// - /// Initializes a new instance of the class. - /// - /// Name of the SQL parameter. - /// Name of the SQL variable. - /// Name of the type as known to the database. - /// Type of the database column as an enum. - /// if set to true is nullable. - /// The maximum length. - /// The precision. - /// The scale. - /// Full name of the type. - /// Indicates the direction of the parameter. - protected ParameterMetadata(string sqlParameterName, string sqlVariableName, string typeName, object? dbType, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, ParameterDirection direction) - { - SqlParameterName = sqlParameterName; - SqlVariableName = sqlVariableName; - TypeName = typeName; - ClrName = Utilities.ToClrName(sqlParameterName); - DbType = dbType; - IsNullable = isNullable; - MaxLength = maxLength; - Precision = precision; - Scale = scale; - FullTypeName = fullTypeName; - Direction = direction; - } - - /// - /// Gets the name used by CLR objects. - /// - public string ClrName { get; } - - /// - /// Gets the type of the database column as an enum. - /// - public object? DbType { get; } - - /// - /// Gets or sets the full name of the type including max length, precision, and/or scale. - /// - /// - /// The full name of the type. - /// - /// This will be null if the data source doesn't support detailed parameter metadata. - public string FullTypeName { get; } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "")] - bool ISqlBuilderEntryDetails.IsIdentity => false; - - /// - /// Gets a value indicating whether this instance is nullable. - /// - /// This will be null if the data source doesn't support detailed parameter metadata. - public bool? IsNullable { get; } - - /// - /// Gets the maximum length. - /// - /// The maximum length. - /// This will be null if the data source doesn't support detailed parameter metadata or if this value isn't applicable to the data type. - public int? MaxLength { get; } - - /// - /// Gets the precision. - /// - /// The precision. - /// This will be null if the data source doesn't support detailed parameter metadata or if this value isn't applicable to the data type. - public int? Precision { get; } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "")] - string? ISqlBuilderEntryDetails.QuotedSqlName => null; - - int? ISqlBuilderEntryDetails.Scale => null; - - /// - /// Gets or sets the scale. - /// - /// The scale. - /// This will be null if the data source doesn't support detailed parameter metadata or if this value isn't applicable to the data type. - public int? Scale { get; } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "")] - string? ISqlBuilderEntryDetails.SqlName => null; - - /// - /// Gets the name used by the database. - /// - public string SqlParameterName { get; } - - /// - /// Gets the name of the SQL variable. - /// - /// The name of the SQL variable. - public string SqlVariableName { get; } - - /// - /// Gets the name of the type as known to the database. - /// - public string TypeName { get; } - - /// - /// Indicates the direction of the parameter. - /// - public ParameterDirection Direction { get; } + SqlParameterName = sqlParameterName; + SqlVariableName = sqlVariableName; + TypeName = typeName; + ClrName = Utilities.ToClrName(sqlParameterName); + DbType = dbType; + IsNullable = isNullable; + MaxLength = maxLength; + Precision = precision; + Scale = scale; + FullTypeName = fullTypeName; + Direction = direction; } + + /// + /// Gets the name used by CLR objects. + /// + public string ClrName { get; } + + /// + /// Gets the type of the database column as an enum. + /// + public object? DbType { get; } + + /// + /// Indicates the direction of the parameter. + /// + public ParameterDirection Direction { get; } + + /// + /// Gets or sets the full name of the type including max length, precision, and/or scale. + /// + /// + /// The full name of the type. + /// + /// This will be null if the data source doesn't support detailed parameter metadata. + public string FullTypeName { get; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "")] + bool ISqlBuilderEntryDetails.IsIdentity => false; + + /// + /// Gets a value indicating whether this instance is nullable. + /// + /// This will be null if the data source doesn't support detailed parameter metadata. + public bool? IsNullable { get; } + + /// + /// Gets the maximum length. + /// + /// The maximum length. + /// This will be null if the data source doesn't support detailed parameter metadata or if this value isn't applicable to the data type. + public int? MaxLength { get; } + + /// + /// Gets the precision. + /// + /// The precision. + /// This will be null if the data source doesn't support detailed parameter metadata or if this value isn't applicable to the data type. + public int? Precision { get; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "")] + string? ISqlBuilderEntryDetails.QuotedSqlName => null; + + int? ISqlBuilderEntryDetails.Scale => null; + + /// + /// Gets or sets the scale. + /// + /// The scale. + /// This will be null if the data source doesn't support detailed parameter metadata or if this value isn't applicable to the data type. + public int? Scale { get; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1033:Interface methods should be callable by child types", Justification = "")] + string? ISqlBuilderEntryDetails.SqlName => null; + + /// + /// Gets the name used by the database. + /// + public string SqlParameterName { get; } + + /// + /// Gets the name of the SQL variable. + /// + /// The name of the SQL variable. + public string SqlVariableName { get; } + + /// + /// Gets the name of the type as known to the database. + /// + public string TypeName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection.cs index 97c08b451..311627d97 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection.cs @@ -1,67 +1,66 @@ using System.Collections; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class ParameterMetadataCollection. +/// +public class ParameterMetadataCollection : IReadOnlyList { + readonly IReadOnlyList m_Source; + /// - /// Class ParameterMetadataCollection. + /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. /// - public class ParameterMetadataCollection : IReadOnlyList + /// The source. + internal ParameterMetadataCollection(IReadOnlyList source) { - readonly IReadOnlyList m_Source; - - /// - /// Initializes a new instance of the IndexColumnMetadataCollection class that is a read-only wrapper around the specified list. - /// - /// The source. - internal ParameterMetadataCollection(IReadOnlyList source) - { - m_Source = source; - } + m_Source = source; + } - /// - /// Gets the number of elements in the collection. - /// - public int Count => m_Source.Count; + /// + /// Gets the number of elements in the collection. + /// + public int Count => m_Source.Count; - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// - public ParameterMetadata this[int index] => m_Source[index]; + /// + /// Gets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// + public ParameterMetadata this[int index] => m_Source[index]; - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return m_Source.GetEnumerator(); - } + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return m_Source.GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() - { - return m_Source.GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() + { + return m_Source.GetEnumerator(); + } - /// - /// Returns the parameter associated with the parameter name. - /// - /// Name of the parameter. - /// - /// If the parameter name was not found, this will return null - public ParameterMetadata? TryGetParameter(string parameterName) - { - foreach (var item in this) - if (item.SqlParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) - return item; + /// + /// Returns the parameter associated with the parameter name. + /// + /// Name of the parameter. + /// + /// If the parameter name was not found, this will return null + public ParameterMetadata? TryGetParameter(string parameterName) + { + foreach (var item in this) + if (item.SqlParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) + return item; - return null; - } + return null; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection`1.cs index 4e67d30b0..15962e986 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadataCollection`1.cs @@ -1,67 +1,66 @@ using System.Collections.ObjectModel; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class ParameterMetadataCollection. +/// +/// The type of the t database type. +public class ParameterMetadataCollection : ReadOnlyCollection> + where TDbType : struct { + readonly string m_Name; + /// - /// Class ParameterMetadataCollection. + /// Initializes a new instance of the class. /// - /// The type of the t database type. - public class ParameterMetadataCollection : ReadOnlyCollection> - where TDbType : struct + /// The name of the parent object. + /// The list to wrap. + public ParameterMetadataCollection(string name, IList> list) : base(list) { - readonly string m_Name; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the parent object. - /// The list to wrap. - public ParameterMetadataCollection(string name, IList> list) : base(list) - { - m_Name = name; - GenericCollection = new ParameterMetadataCollection(this); - } + m_Name = name; + GenericCollection = new ParameterMetadataCollection(this); + } - /// - /// Gets the generic version of this collection. - /// - /// The generic collection. - /// This is used in generic repository scenarios - public ParameterMetadataCollection GenericCollection { get; } + /// + /// Gets the generic version of this collection. + /// + /// The generic collection. + /// This is used in generic repository scenarios + public ParameterMetadataCollection GenericCollection { get; } - /// - /// Gets the with the specified name. - /// - /// Name of the parameter. - /// ParameterMetadata<TDbType>. - /// - public ParameterMetadata this[string parameterName] + /// + /// Gets the with the specified name. + /// + /// Name of the parameter. + /// ParameterMetadata<TDbType>. + /// + public ParameterMetadata this[string parameterName] + { + get { - get - { - foreach (var item in this) - if (item.SqlParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) - return item; + foreach (var item in this) + if (item.SqlParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) + return item; #pragma warning disable CA1065 // Do not raise exceptions in unexpected locations - throw new KeyNotFoundException($"Could not find parameter named {parameterName} in object {m_Name}"); + throw new KeyNotFoundException($"Could not find parameter named {parameterName} in object {m_Name}"); #pragma warning restore CA1065 // Do not raise exceptions in unexpected locations - } } + } - /// - /// Returns the parameter associated with the parameter name. - /// - /// Name of the parameter. - /// - /// If the parameter name was not found, this will return null - public ParameterMetadata? TryGetParameter(string parameterName) - { - foreach (var item in this) - if (item.SqlParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) - return item; + /// + /// Returns the parameter associated with the parameter name. + /// + /// Name of the parameter. + /// + /// If the parameter name was not found, this will return null + public ParameterMetadata? TryGetParameter(string parameterName) + { + foreach (var item in this) + if (item.SqlParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase)) + return item; - return null; - } + return null; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata`1.cs index b8d80f324..7e0ef606f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ParameterMetadata`1.cs @@ -1,47 +1,32 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for a stored procedure parameter +/// +/// The variant of DbType used by this data source. +public sealed class ParameterMetadata : ParameterMetadata, ISqlBuilderEntryDetails + where TDbType : struct { /// - /// Metadata for a stored procedure parameter + /// Initializes a new instance of the class. /// - /// The variant of DbType used by this data source. - public sealed class ParameterMetadata : ParameterMetadata, ISqlBuilderEntryDetails - where TDbType : struct + /// Name of the SQL parameter. + /// Name of the SQL variable. + /// Name of the type as known to the database. + /// Type of the database column as an enum. + /// if set to true is nullable. + /// The maximum length. + /// The precision. + /// The scale. + /// Full name of the type. + /// Indicates the direction of the parameter. + public ParameterMetadata(string sqlParameterName, string sqlVariableName, string typeName, TDbType? dbType, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, ParameterDirection direction) : base(sqlParameterName, sqlVariableName, typeName, dbType, isNullable, maxLength, precision, scale, fullTypeName, direction) { - /* - /// - /// Initializes a new instance of the class. - /// - /// Name of the SQL parameter. - /// Name of the SQL variable. - /// Name of the type as known to the database. - /// Type of the database column as an enum. - public ParameterMetadata(string sqlParameterName, string sqlVariableName, string typeName, TDbType dbType) : base(sqlParameterName, sqlVariableName, typeName, dbType) - { - DbType = dbType; - } - */ - - /// - /// Initializes a new instance of the class. - /// - /// Name of the SQL parameter. - /// Name of the SQL variable. - /// Name of the type as known to the database. - /// Type of the database column as an enum. - /// if set to true is nullable. - /// The maximum length. - /// The precision. - /// The scale. - /// Full name of the type. - /// Indicates the direction of the parameter. - public ParameterMetadata(string sqlParameterName, string sqlVariableName, string typeName, TDbType? dbType, bool? isNullable, int? maxLength, int? precision, int? scale, string fullTypeName, ParameterDirection direction) : base(sqlParameterName, sqlVariableName, typeName, dbType, isNullable, maxLength, precision, scale, fullTypeName, direction) - { - DbType = dbType; - } - - /// - /// Gets the type of the database column as an enum. - /// - public new TDbType? DbType { get; } + DbType = dbType; } + + /// + /// Gets the type of the database column as an enum. + /// + public new TDbType? DbType { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata.cs index 0683b4346..7d615e461 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata.cs @@ -1,91 +1,90 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class TableFunctionMetadata. +/// +public abstract class ScalarFunctionMetadata : DatabaseObject { /// - /// Class TableFunctionMetadata. + /// Initializes a new instance of the class. /// - public abstract class ScalarFunctionMetadata : DatabaseObject + /// The name. + /// The parameters. + /// Name of the type. + /// Type of the database. + /// if set to true [is nullable]. + /// The maximum length. + /// The precision. + /// The scale. + /// Full name of the type. + protected ScalarFunctionMetadata(string name, ParameterMetadataCollection parameters, string typeName, object? dbType, bool isNullable, int? maxLength, int? precision, int? scale, string fullTypeName) : base(name) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The parameters. - /// Name of the type. - /// Type of the database. - /// if set to true [is nullable]. - /// The maximum length. - /// The precision. - /// The scale. - /// Full name of the type. - protected ScalarFunctionMetadata(string name, ParameterMetadataCollection parameters, string typeName, object? dbType, bool isNullable, int? maxLength, int? precision, int? scale, string fullTypeName) : base(name) - { - Parameters = parameters; - TypeName = typeName; - DbType = dbType; - IsNullable = isNullable; - MaxLength = maxLength; - Precision = precision; - Scale = scale; - FullTypeName = fullTypeName; - } + Parameters = parameters; + TypeName = typeName; + DbType = dbType; + IsNullable = isNullable; + MaxLength = maxLength; + Precision = precision; + Scale = scale; + FullTypeName = fullTypeName; + } - /// - /// Gets the type used by the database. - /// - public object? DbType { get; } + /// + /// Gets the type used by the database. + /// + public object? DbType { get; } - /// - /// Gets or sets the full name of the type including max length, precision, and/or scale. - /// - /// - /// The full name of the type. - /// - public string FullTypeName { get; } + /// + /// Gets or sets the full name of the type including max length, precision, and/or scale. + /// + /// + /// The full name of the type. + /// + public string FullTypeName { get; } - /// - /// Gets or sets a value indicating whether this column is nullable. - /// - /// - /// true if this column is nullable; otherwise, false. - /// - public bool IsNullable { get; } + /// + /// Gets or sets a value indicating whether this column is nullable. + /// + /// + /// true if this column is nullable; otherwise, false. + /// + public bool IsNullable { get; } - /// - /// Gets or sets the maximum length. - /// - /// - /// The maximum length. - /// - public int? MaxLength { get; } + /// + /// Gets or sets the maximum length. + /// + /// + /// The maximum length. + /// + public int? MaxLength { get; } - /// - /// Gets the parameters. - /// - /// - /// The parameters. - /// - public ParameterMetadataCollection Parameters { get; } + /// + /// Gets the parameters. + /// + /// + /// The parameters. + /// + public ParameterMetadataCollection Parameters { get; } - /// - /// Gets or sets the precision. - /// - /// - /// The precision. - /// - public int? Precision { get; } + /// + /// Gets or sets the precision. + /// + /// + /// The precision. + /// + public int? Precision { get; } - /// - /// Gets or sets the scale. - /// - /// - /// The scale. - /// - public int? Scale { get; } + /// + /// Gets or sets the scale. + /// + /// + /// The scale. + /// + public int? Scale { get; } - /// - /// Gets the name of the type. - /// - /// The name of the type. - public string TypeName { get; } - } + /// + /// Gets the name of the type. + /// + /// The name of the type. + public string TypeName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata`2.cs index 9e8de352c..4b9149c0b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/ScalarFunctionMetadata`2.cs @@ -1,64 +1,63 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for a database table value function. +/// +/// The type used to represent database object names. +/// The variant of DbType used by this data source. +public sealed class ScalarFunctionMetadata : ScalarFunctionMetadata + where TObjectName : struct + where TDbType : struct { + readonly SqlBuilder m_Builder; + /// - /// Metadata for a database table value function. + /// Initializes a new instance of the class. /// - /// The type used to represent database object names. - /// The variant of DbType used by this data source. - public sealed class ScalarFunctionMetadata : ScalarFunctionMetadata - where TObjectName : struct - where TDbType : struct + /// The name of the scalar function. + /// The parameters. + /// Name of the return type. + /// Return type. + /// if set to true if the return type is nullable. + /// The maximum length of the return value. + /// The precision of the return value. + /// The scale of the return value. + /// Full name of the return type. + public ScalarFunctionMetadata(TObjectName name, ParameterMetadataCollection parameters, string typeName, TDbType? dbType, bool isNullable, int? maxLength, int? precision, int? scale, string fullTypeName) : base(name.ToString()!, parameters?.GenericCollection!, typeName, dbType, isNullable, maxLength, precision, scale, fullTypeName) { - readonly SqlBuilder m_Builder; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the scalar function. - /// The parameters. - /// Name of the return type. - /// Return type. - /// if set to true if the return type is nullable. - /// The maximum length of the return value. - /// The precision of the return value. - /// The scale of the return value. - /// Full name of the return type. - public ScalarFunctionMetadata(TObjectName name, ParameterMetadataCollection parameters, string typeName, TDbType? dbType, bool isNullable, int? maxLength, int? precision, int? scale, string fullTypeName) : base(name.ToString()!, parameters?.GenericCollection!, typeName, dbType, isNullable, maxLength, precision, scale, fullTypeName) - { - Name = name; - Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null"); - m_Builder = new SqlBuilder(Name.ToString()!, Parameters); - DbType = dbType; - } + Name = name; + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null"); + m_Builder = new SqlBuilder(Name.ToString()!, Parameters); + DbType = dbType; + } - /// - /// Gets the return type used by the database. - /// - public new TDbType? DbType { get; } + /// + /// Gets the return type used by the database. + /// + public new TDbType? DbType { get; } - /// - /// Gets the name. - /// - /// - /// The name. - /// - public new TObjectName Name { get; } + /// + /// Gets the name. + /// + /// + /// The name. + /// + public new TObjectName Name { get; } - /// - /// Gets the parameters. - /// - /// - /// The parameters. - /// - public new ParameterMetadataCollection Parameters { get; } + /// + /// Gets the parameters. + /// + /// + /// The parameters. + /// + public new ParameterMetadataCollection Parameters { get; } - /// - /// Creates a SQL builder. - /// - /// if set to true [strict mode]. - /// - public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); - } + /// + /// Creates a SQL builder. + /// + /// if set to true [strict mode]. + /// + public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata.cs index b237fd01b..9942bb171 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata.cs @@ -1,28 +1,27 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class StoredProcedureMetadata. +/// +public abstract class StoredProcedureMetadata : DatabaseObject { /// - /// Class StoredProcedureMetadata. + /// Initializes a new instance of the class. /// - public abstract class StoredProcedureMetadata : DatabaseObject + /// The name. + /// The parameters. + /// name + /// parameters + protected StoredProcedureMetadata(string name, ParameterMetadataCollection parameters) : base(name) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The parameters. - /// name - /// parameters - protected StoredProcedureMetadata(string name, ParameterMetadataCollection parameters) : base(name) - { - Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); - } - - /// - /// Gets the parameters. - /// - /// - /// The parameters. - /// - public ParameterMetadataCollection Parameters { get; } + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); } + + /// + /// Gets the parameters. + /// + /// + /// The parameters. + /// + public ParameterMetadataCollection Parameters { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata`2.cs index 53b038401..f94e2dd59 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/StoredProcedureMetadata`2.cs @@ -1,51 +1,50 @@ using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class StoredProcedureMetadata. +/// +/// The type used to represent database object names. +/// The variant of DbType used by this data source. +public sealed class StoredProcedureMetadata : StoredProcedureMetadata + where TObjectName : struct + where TDbType : struct { + readonly SqlBuilder m_Builder; + /// - /// Class StoredProcedureMetadata. + /// Initializes a new instance of the class. /// - /// The type used to represent database object names. - /// The variant of DbType used by this data source. - public sealed class StoredProcedureMetadata : StoredProcedureMetadata - where TObjectName : struct - where TDbType : struct + /// The name. + /// The parameters. + public StoredProcedureMetadata(TObjectName name, ParameterMetadataCollection parameters) : base(name.ToString()!, parameters?.GenericCollection!) { - readonly SqlBuilder m_Builder; - - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The parameters. - public StoredProcedureMetadata(TObjectName name, ParameterMetadataCollection parameters) : base(name.ToString()!, parameters?.GenericCollection!) - { - Name = name; - Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); + Name = name; + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); - m_Builder = new SqlBuilder(Name.ToString()!, Parameters); - } + m_Builder = new SqlBuilder(Name.ToString()!, Parameters); + } - /// - /// Gets the name. - /// - /// - /// The name. - /// - public new TObjectName Name { get; } + /// + /// Gets the name. + /// + /// + /// The name. + /// + public new TObjectName Name { get; } - /// - /// Gets the parameters. - /// - /// - /// The parameters. - /// - public new ParameterMetadataCollection Parameters { get; } + /// + /// Gets the parameters. + /// + /// + /// The parameters. + /// + public new ParameterMetadataCollection Parameters { get; } - /// - /// Creates a SQL builder. - /// - /// - public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); - } + /// + /// Creates a SQL builder. + /// + /// + public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata.cs index b795720d3..23e39d27b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata.cs @@ -1,52 +1,51 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class TableFunctionMetadata. +/// +public abstract class TableFunctionMetadata : DatabaseObject { /// - /// Class TableFunctionMetadata. + /// Initializes a new instance of the class. /// - public abstract class TableFunctionMetadata : DatabaseObject + /// The name. + /// The parameters. + /// The columns. + /// name + /// + /// parameters + /// or + /// columns + /// + protected TableFunctionMetadata(string name, ParameterMetadataCollection parameters, ColumnMetadataCollection columns) : base(name) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The parameters. - /// The columns. - /// name - /// - /// parameters - /// or - /// columns - /// - protected TableFunctionMetadata(string name, ParameterMetadataCollection parameters, ColumnMetadataCollection columns) : base(name) - { - Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - NullableColumns = new ColumnMetadataCollection(name, columns.Where(c => c.IsNullable == true).ToList()); - } + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + NullableColumns = new ColumnMetadataCollection(name, columns.Where(c => c.IsNullable == true).ToList()); + } - /// - /// Gets the columns. - /// - /// - /// The columns. - /// - public ColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + /// + /// The columns. + /// + public ColumnMetadataCollection Columns { get; } - /// - /// Gets the columns known to be nullable. - /// - /// - /// The nullable columns. - /// - /// This is used to improve the performance of materializers by avoiding is null checks. - public ColumnMetadataCollection NullableColumns { get; } + /// + /// Gets the columns known to be nullable. + /// + /// + /// The nullable columns. + /// + /// This is used to improve the performance of materializers by avoiding is null checks. + public ColumnMetadataCollection NullableColumns { get; } - /// - /// Gets the parameters. - /// - /// - /// The parameters. - /// - public ParameterMetadataCollection Parameters { get; } - } + /// + /// Gets the parameters. + /// + /// + /// The parameters. + /// + public ParameterMetadataCollection Parameters { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata`2.cs index 31f909dcc..3e82ad67b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableFunctionMetadata`2.cs @@ -1,59 +1,78 @@ -using Tortuga.Chain.CommandBuilders; +using System.Collections.Immutable; +using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for a database table value function. +/// +/// The type used to represent database object names. +/// The variant of DbType used by this data source. +public sealed class TableFunctionMetadata : TableFunctionMetadata + where TObjectName : struct + where TDbType : struct { + readonly SqlBuilder m_Builder; + readonly ImmutableArray m_DefaultSortOrder; + + /// Initializes a new instance of the class. + /// The name. + /// The parameters. + /// The columns. + public TableFunctionMetadata(TObjectName name, ParameterMetadataCollection parameters, ColumnMetadataCollection columns) : base(name.ToString()!, parameters?.GenericCollection!, columns?.GenericCollection!) + { + Name = name; + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + m_Builder = new SqlBuilder(Name.ToString()!, Columns, Parameters); + + if (columns.Count == 0) + m_DefaultSortOrder = ImmutableArray.Empty; + else + m_DefaultSortOrder = Columns.Select(c => new SortExpression(c.SqlName)).ToImmutableArray(); + } + + /// + /// Gets the columns. + /// + /// + /// The columns. + /// + public new ColumnMetadataCollection Columns { get; } + + /// + /// Gets the name. + /// + /// + /// The name. + /// + public new TObjectName Name { get; } + + /// + /// Gets the parameters. + /// + /// + /// The parameters. + /// + public new ParameterMetadataCollection Parameters { get; } + + /// + /// Creates a SQL builder. + /// + /// if set to true [strict mode]. + /// + public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); + /// - /// Metadata for a database table value function. + /// Gets the default sort order. This is based on the first N columns. /// - /// The type used to represent database object names. - /// The variant of DbType used by this data source. - public sealed class TableFunctionMetadata : TableFunctionMetadata - where TObjectName : struct - where TDbType : struct + /// Sort by [columnsToUse] columns. If not specified, returns all columns. + /// If no valid sort columns are found, this will return an empty array. + public IEnumerable GetDefaultSortOrder(int columnsToUse = int.MaxValue) { - readonly SqlBuilder m_Builder; - - /// Initializes a new instance of the class. - /// The name. - /// The parameters. - /// The columns. - public TableFunctionMetadata(TObjectName name, ParameterMetadataCollection parameters, ColumnMetadataCollection columns) : base(name.ToString()!, parameters?.GenericCollection!, columns?.GenericCollection!) - { - Name = name; - Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters), $"{nameof(parameters)} is null."); - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - m_Builder = new SqlBuilder(Name.ToString()!, Columns, Parameters); - } - - /// - /// Gets the columns. - /// - /// - /// The columns. - /// - public new ColumnMetadataCollection Columns { get; } - - /// - /// Gets the name. - /// - /// - /// The name. - /// - public new TObjectName Name { get; } - - /// - /// Gets the parameters. - /// - /// - /// The parameters. - /// - public new ParameterMetadataCollection Parameters { get; } - - /// - /// Creates a SQL builder. - /// - /// if set to true [strict mode]. - /// - public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); + if (columnsToUse >= m_DefaultSortOrder.Length) + return m_DefaultSortOrder; + else + return m_DefaultSortOrder.Take(columnsToUse); } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata.cs index 4da34bd16..05fb3b3a1 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata.cs @@ -1,84 +1,83 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Class DatabaseObject. +/// +public abstract class DatabaseObject { - /// - /// Class DatabaseObject. - /// - public abstract class DatabaseObject + /// Initializes a new instance of the class. + protected DatabaseObject(string name) { - /// Initializes a new instance of the class. - protected DatabaseObject(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentException($"{nameof(name)} is null or empty.", nameof(name)); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException($"{nameof(name)} is null or empty.", nameof(name)); - Name = name; - } - - /// - /// Gets the name. - /// - /// - /// The name. - /// - public string Name { get; } + Name = name; } /// - /// Abstract version of TableOrViewMetadata. + /// Gets the name. /// - public abstract class TableOrViewMetadata : DatabaseObject + /// + /// The name. + /// + public string Name { get; } +} + +/// +/// Abstract version of TableOrViewMetadata. +/// +public abstract class TableOrViewMetadata : DatabaseObject +{ + /// Initializes a new instance of the class. + protected TableOrViewMetadata(string name, bool isTable, ColumnMetadataCollection columns) : base(name) { - /// Initializes a new instance of the class. - protected TableOrViewMetadata(string name, bool isTable, ColumnMetadataCollection columns) : base(name) - { - IsTable = isTable; - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - NonNullableColumns = new ColumnMetadataCollection(name, columns.Where(c => c.IsNullable == false).ToList()); - PrimaryKeyColumns = new ColumnMetadataCollection(name, columns.Where(c => c.IsPrimaryKey).ToList()); - } + IsTable = isTable; + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + NonNullableColumns = new ColumnMetadataCollection(name, columns.Where(c => c.IsNullable == false).ToList()); + PrimaryKeyColumns = new ColumnMetadataCollection(name, columns.Where(c => c.IsPrimaryKey).ToList()); + } - /// - /// Gets the columns. - /// - /// - /// The columns. - /// - public ColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + /// + /// The columns. + /// + public ColumnMetadataCollection Columns { get; } - /// - /// Gets a value indicating whether this table or view has primary key. - /// - /// - /// true if this instance has a primary key; otherwise, false. - /// - public bool HasPrimaryKey => Columns.Any(c => c.IsPrimaryKey); + /// + /// Gets a value indicating whether this table or view has primary key. + /// + /// + /// true if this instance has a primary key; otherwise, false. + /// + public bool HasPrimaryKey => Columns.Any(c => c.IsPrimaryKey); - /// - /// Gets a value indicating whether this instance is table or a view. - /// - /// - /// true if this instance is a table; otherwise, false. - /// - public bool IsTable { get; } + /// + /// Gets a value indicating whether this instance is table or a view. + /// + /// + /// true if this instance is a table; otherwise, false. + /// + public bool IsTable { get; } - /// - /// Gets the columns known to be not nullable. - /// - /// - /// The nullable columns. - /// - /// This is used to improve the performance of materializers by avoiding is null checks. - [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public ColumnMetadataCollection NonNullableColumns { get; } + /// + /// Gets the columns known to be not nullable. + /// + /// + /// The nullable columns. + /// + /// This is used to improve the performance of materializers by avoiding is null checks. + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public ColumnMetadataCollection NonNullableColumns { get; } - /// - /// Gets the columns that make up the primary key. - /// - /// - /// The columns. - /// - public ColumnMetadataCollection PrimaryKeyColumns { get; } - } + /// + /// Gets the columns that make up the primary key. + /// + /// + /// The columns. + /// + public ColumnMetadataCollection PrimaryKeyColumns { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata`2.cs index 122f0e5ad..7a86a9383 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TableOrViewMetadata`2.cs @@ -1,88 +1,109 @@ -using Tortuga.Chain.CommandBuilders; +using System.Collections.Immutable; +using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// Metadata for a database table or view. +/// +/// The type used to represent database object names. +/// The variant of DbType used by this data source. +public class TableOrViewMetadata : TableOrViewMetadata + where TObjectName : struct + where TDbType : struct { + readonly SqlBuilder m_Builder; + readonly ImmutableArray m_DefaultSortOrder; + readonly DatabaseMetadataCache m_MetadataCache; + ForeignKeyConstraintCollection? m_ForeignKeys; + IndexMetadataCollection? m_Indexes; + /// - /// Metadata for a database table or view. + /// Initializes a new instance of the class. /// - /// The type used to represent database object names. - /// The variant of DbType used by this data source. - public class TableOrViewMetadata : TableOrViewMetadata - where TObjectName : struct - where TDbType : struct + /// The metadata cache. + /// The name. + /// if set to true [is table]. + /// The columns. + public TableOrViewMetadata(DatabaseMetadataCache metadataCache, TObjectName name, bool isTable, ColumnMetadataCollection columns) : base(name.ToString()!, isTable, columns?.GenericCollection!) { - readonly SqlBuilder m_Builder; - readonly DatabaseMetadataCache m_MetadataCache; - ForeignKeyConstraintCollection? m_ForeignKeys; - IndexMetadataCollection? m_Indexes; + m_MetadataCache = metadataCache ?? throw new ArgumentNullException(nameof(metadataCache), $"{nameof(metadataCache)} is null."); + Name = name; + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + PrimaryKeyColumns = new ColumnMetadataCollection(name.ToString()!, columns.Where(c => c.IsPrimaryKey).ToList()); + m_Builder = new SqlBuilder(Name.ToString()!, Columns); - /// - /// Initializes a new instance of the class. - /// - /// The metadata cache. - /// The name. - /// if set to true [is table]. - /// The columns. - public TableOrViewMetadata(DatabaseMetadataCache metadataCache, TObjectName name, bool isTable, ColumnMetadataCollection columns) : base(name.ToString()!, isTable, columns?.GenericCollection!) - { - m_MetadataCache = metadataCache ?? throw new ArgumentNullException(nameof(metadataCache), $"{nameof(metadataCache)} is null."); - Name = name; - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - PrimaryKeyColumns = new ColumnMetadataCollection(name.ToString()!, columns.Where(c => c.IsPrimaryKey).ToList()); - m_Builder = new SqlBuilder(Name.ToString()!, Columns); - } + if (columns.Count == 0) + m_DefaultSortOrder = ImmutableArray.Empty; + else if (HasPrimaryKey) + m_DefaultSortOrder = PrimaryKeyColumns.Select(c => new SortExpression(c.SqlName)).ToImmutableArray(); + else + m_DefaultSortOrder = Columns.Select(c => new SortExpression(c.SqlName)).ToImmutableArray(); + } - /// - /// Gets the columns. - /// - /// - /// The columns. - /// - public new ColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + /// + /// The columns. + /// + public new ColumnMetadataCollection Columns { get; } - /// - /// Gets the name. - /// - /// - /// The name. - /// - public new TObjectName Name { get; } + /// + /// Gets the name. + /// + /// + /// The name. + /// + public new TObjectName Name { get; } - /// - /// Gets the columns that make up the primary key. - /// - /// - /// The columns. - /// - public new ColumnMetadataCollection PrimaryKeyColumns { get; } + /// + /// Gets the columns that make up the primary key. + /// + /// + /// The columns. + /// + public new ColumnMetadataCollection PrimaryKeyColumns { get; } - /// - /// Creates the SQL builder - /// - /// - public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); + /// + /// Creates the SQL builder + /// + /// + public SqlBuilder CreateSqlBuilder(bool strictMode) => m_Builder.Clone(strictMode); - /// - /// Gets the indexes for this table or view. - /// - /// - /// Indexes are not supported by this data source - public ForeignKeyConstraintCollection GetForeignKeys() - { - if (m_ForeignKeys == null) - m_ForeignKeys = m_MetadataCache.GetForeignKeysForTable(Name); - return m_ForeignKeys; - } + /// + /// Gets the default sort order. This will be the primary key(s) if they exist. Otherwise the columns will be used in declared order. + /// + /// Sort by [columnsToUse] columns. If not specified, returns all columns in the default sort. + /// If no valid sort columns are found, this will return an empty array. + public IEnumerable GetDefaultSortOrder(int columnsToUse = int.MaxValue) + { + if (columnsToUse >= m_DefaultSortOrder.Length) + return m_DefaultSortOrder; + else + return m_DefaultSortOrder.Take(columnsToUse); + } - /// - /// Gets the indexes for this table or view. - /// - /// - public IndexMetadataCollection GetIndexes() - { - if (m_Indexes == null) - m_Indexes = m_MetadataCache.GetIndexesForTable(Name); - return m_Indexes; - } + /// + /// Gets the indexes for this table or view. + /// + /// + /// Indexes are not supported by this data source + public ForeignKeyConstraintCollection GetForeignKeys() + { + if (m_ForeignKeys == null) + m_ForeignKeys = m_MetadataCache.GetForeignKeysForTable(Name); + return m_ForeignKeys; + } + + /// + /// Gets the indexes for this table or view. + /// + /// + public IndexMetadataCollection GetIndexes() + { + if (m_Indexes == null) + m_Indexes = m_MetadataCache.GetIndexesForTable(Name); + return m_Indexes; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TypeRegistration`1.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TypeRegistration`1.cs index 980b7164b..b94e82865 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TypeRegistration`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/TypeRegistration`1.cs @@ -1,46 +1,45 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This is used to map custom database types to CLR types +/// +/// The type of the database type. +public class TypeRegistration { /// - /// This is used to map custom database types to CLR types + /// Initializes a new instance of the TypeRegistration class. /// - /// The type of the database type. - public class TypeRegistration + /// Name of the database type. + /// Type of the database. + /// Type of the color. + public TypeRegistration(string databaseTypeName, TDbType databaseType, Type clrType) { - /// - /// Initializes a new instance of the TypeRegistration class. - /// - /// Name of the database type. - /// Type of the database. - /// Type of the color. - public TypeRegistration(string databaseTypeName, TDbType databaseType, Type clrType) - { - DatabaseType = databaseType; - DatabaseTypeName = databaseTypeName; - ClrType = clrType; - } + DatabaseType = databaseType; + DatabaseTypeName = databaseTypeName; + ClrType = clrType; + } - /// - /// Gets the type of the CLR type. - /// - /// - /// The type of the CLR type. - /// - public Type ClrType { get; } + /// + /// Gets the type of the CLR type. + /// + /// + /// The type of the CLR type. + /// + public Type ClrType { get; } - /// - /// Gets the type of the database column. - /// - /// - /// The type of the database column. - /// - public TDbType DatabaseType { get; } + /// + /// Gets the type of the database column. + /// + /// + /// The type of the database column. + /// + public TDbType DatabaseType { get; } - /// - /// Gets the name of the database column type. - /// - /// - /// The name of the database column type. - /// - public string DatabaseTypeName { get; } - } + /// + /// Gets the name of the database column type. + /// + /// + /// The name of the database column type. + /// + public string DatabaseTypeName { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTableTypeMetadata.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTableTypeMetadata.cs index dc905773b..458c2d474 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTableTypeMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTableTypeMetadata.cs @@ -1,40 +1,39 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This represents user defined table types in the database. +/// +public abstract class UserDefinedTableTypeMetadata { /// - /// This represents user defined table types in the database. + /// Initializes a new instance of the class. /// - public abstract class UserDefinedTableTypeMetadata + /// The name. + /// The columns. + /// name + /// columns + protected UserDefinedTableTypeMetadata(string name, ColumnMetadataCollection columns) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The columns. - /// name - /// columns - protected UserDefinedTableTypeMetadata(string name, ColumnMetadataCollection columns) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentException($"{nameof(name)} is null or empty.", nameof(name)); + if (string.IsNullOrEmpty(name)) + throw new ArgumentException($"{nameof(name)} is null or empty.", nameof(name)); - Name = name; - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - } + Name = name; + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + } - /// - /// Gets the columns. - /// - /// - /// The columns. - /// - public ColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + /// + /// The columns. + /// + public ColumnMetadataCollection Columns { get; } - /// - /// Gets the name. - /// - /// - /// The name. - /// - public string Name { get; } - } + /// + /// Gets the name. + /// + /// + /// The name. + /// + public string Name { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTypeMetadata`2.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTypeMetadata`2.cs index 14a3301e7..0102d9109 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTypeMetadata`2.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/UserDefinedTypeMetadata`2.cs @@ -1,40 +1,39 @@ -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +/// +/// This class represents user defined table types. +/// +/// The type of the t name. +/// The type of the t database type. +public sealed class UserDefinedTableTypeMetadata : UserDefinedTableTypeMetadata + where TObjectName : struct + where TDbType : struct { /// - /// This class represents user defined table types. + /// Initializes a new instance of the class. /// - /// The type of the t name. - /// The type of the t database type. - public sealed class UserDefinedTableTypeMetadata : UserDefinedTableTypeMetadata - where TObjectName : struct - where TDbType : struct + /// The name. + /// The columns. + public UserDefinedTableTypeMetadata(TObjectName name, ColumnMetadataCollection columns) + : base(name.ToString()!, columns?.GenericCollection!) { - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The columns. - public UserDefinedTableTypeMetadata(TObjectName name, ColumnMetadataCollection columns) - : base(name.ToString()!, columns?.GenericCollection!) - { - Name = name; - Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); - } + Name = name; + Columns = columns ?? throw new ArgumentNullException(nameof(columns), $"{nameof(columns)} is null."); + } - /// - /// Gets the columns. - /// - /// - /// The columns. - /// - public new ColumnMetadataCollection Columns { get; } + /// + /// Gets the columns. + /// + /// + /// The columns. + /// + public new ColumnMetadataCollection Columns { get; } - /// - /// Gets the name. - /// - /// - /// The name. - /// - public new TObjectName Name { get; } - } + /// + /// Gets the name. + /// + /// + /// The name. + /// + public new TObjectName Name { get; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/Utilities.cs index 62ef1248a..b445bc452 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Metadata/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Metadata/Utilities.cs @@ -1,35 +1,34 @@ using System.Globalization; -namespace Tortuga.Chain.Metadata +namespace Tortuga.Chain.Metadata; + +internal static class Utilities { - internal static class Utilities + static readonly char[] s_InvalidCharacters = new char[] { ' ', '.', ',', '$', '@' }; + + public static string QuotedSqlNameSafe(this ISqlBuilderEntryDetails details) { - static readonly char[] s_InvalidCharacters = new char[] { ' ', '.', ',', '$', '@' }; + var value = details.QuotedSqlName; + if (string.IsNullOrEmpty(value)) + throw new InvalidOperationException($"Using parameter {details.SqlVariableName} as a column is not allowed because QuotedSqlName is missing."); - public static string QuotedSqlNameSafe(this ISqlBuilderEntryDetails details) - { - var value = details.QuotedSqlName; - if (string.IsNullOrEmpty(value)) - throw new InvalidOperationException($"Using parameter {details.SqlVariableName} as a column is not allowed because QuotedSqlName is missing."); + return value!; + } - return value!; - } + public static string ToClrName(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentException($"{nameof(name)} is null or empty.", nameof(name)); - public static string ToClrName(string name) + string result = name; + foreach (char c in s_InvalidCharacters) { - if (string.IsNullOrEmpty(name)) - throw new ArgumentException($"{nameof(name)} is null or empty.", nameof(name)); - - string result = name; - foreach (char c in s_InvalidCharacters) - { - result = result.Replace(c.ToString(CultureInfo.InvariantCulture), "", StringComparison.Ordinal); - } + result = result.Replace(c.ToString(CultureInfo.InvariantCulture), "", StringComparison.Ordinal); + } - if (!char.IsLetter(result[0]) && result[0] != '_') - result = "_" + result; + if (!char.IsLetter(result[0]) && result[0] != '_') + result = "_" + result; - return result; - } + return result; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/MetadataException.cs b/Tortuga.Chain/Tortuga.Chain.Core/MetadataException.cs index 645dded66..cbb211a04 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/MetadataException.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/MetadataException.cs @@ -1,47 +1,45 @@ - -using System.Runtime.Serialization; +using System.Runtime.Serialization; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Error loading the schema metadata from the database. +/// +/// + +[Serializable] +public class MetadataException : Exception { /// - /// Error loading the schema metadata from the database. + /// Initializes a new instance of the class. /// - /// - - [Serializable] - public class MetadataException : Exception + public MetadataException() { - /// - /// Initializes a new instance of the class. - /// - public MetadataException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public MetadataException(string message) : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public MetadataException(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. - public MetadataException(string message, Exception innerException) : base(message, innerException) - { - } + /// + /// 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. + public MetadataException(string message, Exception innerException) : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - protected MetadataException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected MetadataException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/MissingDataException.cs b/Tortuga.Chain/Tortuga.Chain.Core/MissingDataException.cs index a43c2825d..da1493394 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/MissingDataException.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/MissingDataException.cs @@ -1,48 +1,47 @@ using System.Runtime.Serialization; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This exception indicates that the expected data was not found. +/// +/// This can occur when a null or empty result set is returned from the database. +[Serializable] +public class MissingDataException : DataException { /// - /// This exception indicates that the expected data was not found. + /// Initializes a new instance of the class. /// - /// This can occur when a null or empty result set is returned from the database. - [Serializable] - public class MissingDataException : DataException + public MissingDataException() { - /// - /// Initializes a new instance of the class. - /// - public MissingDataException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public MissingDataException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public MissingDataException(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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. - public MissingDataException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// 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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. + public MissingDataException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The data necessary to serialize or deserialize an object. - /// Description of the source and destination of the specified serialized stream. - protected MissingDataException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The data necessary to serialize or deserialize an object. + /// Description of the source and destination of the specified serialized stream. + protected MissingDataException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/MissingObjectException.cs b/Tortuga.Chain/Tortuga.Chain.Core/MissingObjectException.cs index 7ca6b43e8..499a7e93a 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/MissingObjectException.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/MissingObjectException.cs @@ -1,46 +1,45 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This exception is thrown when the requested database object (e.g. table, view, etc.) could not be found. +/// + +[Serializable] +public class MissingObjectException : Exception { /// - /// This exception is thrown when the requested database object (e.g. table, view, etc.) could not be found. + /// Initializes a new instance of the class. /// - - [Serializable] - public class MissingObjectException : Exception + public MissingObjectException() { - /// - /// Initializes a new instance of the class. - /// - public MissingObjectException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public MissingObjectException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public MissingObjectException(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. - public MissingObjectException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// 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. + public MissingObjectException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. - protected MissingObjectException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected MissingObjectException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/ObjectDataReader.cs b/Tortuga.Chain/Tortuga.Chain.Core/ObjectDataReader.cs index ba12d781d..0b5a5d3ca 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/ObjectDataReader.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/ObjectDataReader.cs @@ -6,483 +6,484 @@ using Tortuga.Chain.AuditRules; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Creates a DbDataReader wrapper over a list of objects. +/// +/// +/// +[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] +[SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")] +public class ObjectDataReader : DbDataReader { + readonly ImmutableArray m_PropertyList; + readonly ImmutableDictionary m_PropertyLookup; + readonly int? m_RecordCount; + readonly DataTable m_Schema; + IEnumerator? m_Source; + /// - /// Creates a DbDataReader wrapper over a list of objects. + /// Initializes a new instance of the class. /// - /// - /// - [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] - [SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")] - public class ObjectDataReader : DbDataReader + /// Type of the table. + /// The source. + /// Type of the operation being performed. + public ObjectDataReader(UserDefinedTableTypeMetadata tableType, IEnumerable source, OperationTypes operationType = OperationTypes.None) { - readonly ImmutableArray m_PropertyList; - readonly ImmutableDictionary m_PropertyLookup; - readonly int? m_RecordCount; - readonly DataTable m_Schema; - IEnumerator? m_Source; - - /// - /// Initializes a new instance of the class. - /// - /// Type of the table. - /// The source. - /// Type of the operation being performed. - public ObjectDataReader(UserDefinedTableTypeMetadata tableType, IEnumerable source, OperationTypes operationType = OperationTypes.None) - { - if (tableType == null) - throw new ArgumentNullException(nameof(tableType), $"{nameof(tableType)} is null."); - if (source == null) - throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); - - //Don't use IEnumerable.Count(), as we don't want to preemptively materialize a lazy collection - if (source is ICollection collection) - m_RecordCount = collection.Count; - - m_Source = source.GetEnumerator(); - var metadata = BuildStructure(tableType.Name, tableType.Columns, true, operationType); - m_Schema = metadata.Schema; - m_PropertyList = metadata.Properties; - m_PropertyLookup = metadata.PropertyLookup; - } + if (tableType == null) + throw new ArgumentNullException(nameof(tableType), $"{nameof(tableType)} is null."); + if (source == null) + throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); + + //Don't use IEnumerable.Count(), as we don't want to preemptively materialize a lazy collection + if (source is ICollection collection) + m_RecordCount = collection.Count; + + m_Source = source.GetEnumerator(); + var metadata = BuildStructure(tableType.Name, tableType.Columns, true, operationType); + m_Schema = metadata.Schema; + m_PropertyList = metadata.Properties; + m_PropertyLookup = metadata.PropertyLookup; + } - /// - /// Initializes a new instance of the class. - /// - /// The table or view. - /// The source. - /// Type of the operation being performed. - public ObjectDataReader(TableOrViewMetadata tableOrView, IEnumerable source, OperationTypes operationType = OperationTypes.None) - { - if (tableOrView == null) - throw new ArgumentNullException(nameof(tableOrView), $"{nameof(tableOrView)} is null."); - if (source == null) - throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); - - //Don't use IEnumerable.Count(), as we don't want to preemptively materialize a lazy collection - if (source is ICollection collection) - m_RecordCount = collection.Count; - - m_Source = source.GetEnumerator(); - var metadata = BuildStructure(tableOrView.Name, tableOrView.Columns, false, operationType); - m_Schema = metadata.Schema; - m_PropertyList = metadata.Properties; - m_PropertyLookup = metadata.PropertyLookup; - } + /// + /// Initializes a new instance of the class. + /// + /// The table or view. + /// The source. + /// Type of the operation being performed. + public ObjectDataReader(TableOrViewMetadata tableOrView, IEnumerable source, OperationTypes operationType = OperationTypes.None) + { + if (tableOrView == null) + throw new ArgumentNullException(nameof(tableOrView), $"{nameof(tableOrView)} is null."); + if (source == null) + throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); + + //Don't use IEnumerable.Count(), as we don't want to preemptively materialize a lazy collection + if (source is ICollection collection) + m_RecordCount = collection.Count; + + m_Source = source.GetEnumerator(); + var metadata = BuildStructure(tableOrView.Name, tableOrView.Columns, false, operationType); + m_Schema = metadata.Schema; + m_PropertyList = metadata.Properties; + m_PropertyLookup = metadata.PropertyLookup; + } - /// - /// Gets a value indicating the depth of nesting for the current row. - /// - /// The depth. - public override int Depth => 0; - - /// - /// Gets the number of columns in the current row. - /// - /// The field count. - public override int FieldCount => m_PropertyList.Length; - - /// - /// Gets a value that indicates whether this contains one or more rows. - /// - /// true if this instance has rows; otherwise, false. - public override bool HasRows => true; - - /// - /// Gets a value indicating whether the is closed. - /// - /// true if this instance is closed; otherwise, false. - public override bool IsClosed => m_Source != null; - - /// - /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. - /// - /// The records affected. - public override int RecordsAffected => m_RecordCount ?? -1; - - /// - /// Gets the with the specified name. - /// - /// The name. - /// System.Object. - public override object? this[string name] - { + /// + /// Gets a value indicating the depth of nesting for the current row. + /// + /// The depth. + public override int Depth => 0; + + /// + /// Gets the number of columns in the current row. + /// + /// The field count. + public override int FieldCount => m_PropertyList.Length; + + /// + /// Gets a value that indicates whether this contains one or more rows. + /// + /// true if this instance has rows; otherwise, false. + public override bool HasRows => true; + + /// + /// Gets a value indicating whether the is closed. + /// + /// true if this instance is closed; otherwise, false. + public override bool IsClosed => m_Source != null; + + /// + /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. + /// + /// The records affected. + public override int RecordsAffected => m_RecordCount ?? -1; + + /// + /// Gets the with the specified name. + /// + /// The name. + /// System.Object. + public override object? this[string name] + { #pragma warning disable CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes). - get + get #pragma warning restore CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes). - { - if (m_Source == null) - throw new ObjectDisposedException(nameof(ObjectDataReader)); + { + if (m_Source == null) + throw new ObjectDisposedException(nameof(ObjectDataReader)); - return m_PropertyList[m_PropertyLookup[name]].InvokeGet(m_Source.Current!); - } + return m_PropertyList[m_PropertyLookup[name]].InvokeGet(m_Source.Current!); } + } - /// - /// Gets the with the specified ordinal. - /// - /// The ordinal. - /// System.Object. - public override object? this[int ordinal] - { + /// + /// Gets the with the specified ordinal. + /// + /// The ordinal. + /// System.Object. + public override object? this[int ordinal] + { #pragma warning disable CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes). - get + get #pragma warning restore CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes). - { - if (m_Source == null) - throw new ObjectDisposedException(nameof(ObjectDataReader)); + { + if (m_Source == null) + throw new ObjectDisposedException(nameof(ObjectDataReader)); - return m_PropertyList[ordinal].InvokeGet(m_Source.Current!); - } + return m_PropertyList[ordinal].InvokeGet(m_Source.Current!); } + } - /// - /// Closes the object. - /// - public override void Close() => Dispose(); - - /// - /// Gets the value of the specified column as a Boolean. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override bool GetBoolean(int ordinal) => (bool)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a byte. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override byte GetByte(int ordinal) => (byte)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Reads a stream of bytes from the specified column, starting at location indicated by , into the buffer, starting at the location indicated by . - /// - /// The zero-based column ordinal. - /// The index within the row from which to begin the read operation. - /// The buffer into which to copy the data. - /// The index with the buffer to which the data will be copied. - /// The maximum number of characters to read. - /// The actual number of bytes read. - /// - public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length) - { - throw new NotImplementedException(); - } + /// + /// Closes the object. + /// + public override void Close() => Dispose(); + + /// + /// Gets the value of the specified column as a Boolean. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override bool GetBoolean(int ordinal) => (bool)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a byte. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override byte GetByte(int ordinal) => (byte)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - /// - /// Gets the value of the specified column as a single character. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override char GetChar(int ordinal) => (char)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Reads a stream of characters from the specified column, starting at location indicated by , into the buffer, starting at the location indicated by . - /// - /// The zero-based column ordinal. - /// The index within the row from which to begin the read operation. - /// The buffer into which to copy the data. - /// The index with the buffer to which the data will be copied. - /// The maximum number of characters to read. - /// The actual number of characters read. + /// + /// Reads a stream of bytes from the specified column, starting at location indicated by , into the buffer, starting at the location indicated by . + /// + /// The zero-based column ordinal. + /// The index within the row from which to begin the read operation. + /// The buffer into which to copy the data. + /// The index with the buffer to which the data will be copied. + /// The maximum number of characters to read. + /// The actual number of bytes read. + /// + public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length) + { + throw new NotImplementedException(); + } + + /// + /// Gets the value of the specified column as a single character. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override char GetChar(int ordinal) => (char)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Reads a stream of characters from the specified column, starting at location indicated by , into the buffer, starting at the location indicated by . + /// + /// The zero-based column ordinal. + /// The index within the row from which to begin the read operation. + /// The buffer into which to copy the data. + /// The index with the buffer to which the data will be copied. + /// The maximum number of characters to read. + /// The actual number of characters read. #pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). - public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) + public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) #pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). - { - var s = GetString(ordinal); - if (length + dataOffset > s.Length) - length = s.Length - (int)dataOffset; + { + var s = GetString(ordinal); + if (length + dataOffset > s.Length) + length = s.Length - (int)dataOffset; - s.CopyTo((int)dataOffset, buffer, bufferOffset, length); - return length; - } + s.CopyTo((int)dataOffset, buffer, bufferOffset, length); + return length; + } - /// - /// Gets name of the data type of the specified column. - /// - /// The zero-based column ordinal. - /// A string representing the name of the data type. - public override string GetDataTypeName(int ordinal) => (string)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a object. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override DateTime GetDateTime(int ordinal) => (DateTime)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a object. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override decimal GetDecimal(int ordinal) => (decimal)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a double-precision floating point number. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override double GetDouble(int ordinal) => (double)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Returns an that can be used to iterate through the rows in the data reader. - /// - /// An that can be used to iterate through the rows in the data reader. - public override IEnumerator GetEnumerator() - { - if (m_Source == null) - throw new ObjectDisposedException(nameof(ObjectDataReader)); + /// + /// Gets name of the data type of the specified column. + /// + /// The zero-based column ordinal. + /// A string representing the name of the data type. + public override string GetDataTypeName(int ordinal) => (string)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - return m_Source; - } + /// + /// Gets the value of the specified column as a object. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override DateTime GetDateTime(int ordinal) => (DateTime)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a object. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override decimal GetDecimal(int ordinal) => (decimal)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a double-precision floating point number. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override double GetDouble(int ordinal) => (double)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Returns an that can be used to iterate through the rows in the data reader. + /// + /// An that can be used to iterate through the rows in the data reader. + public override IEnumerator GetEnumerator() + { + if (m_Source == null) + throw new ObjectDisposedException(nameof(ObjectDataReader)); - /// - /// Gets the data type of the specified column. - /// - /// The zero-based column ordinal. - /// The data type of the specified column. - public override Type GetFieldType(int ordinal) => m_PropertyList[ordinal].PropertyType; - - /// - /// Gets the value of the specified column as a single-precision floating point number. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override float GetFloat(int ordinal) => (float)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a globally-unique identifier (GUID). - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override Guid GetGuid(int ordinal) => (Guid)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a 16-bit signed integer. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override short GetInt16(int ordinal) => (short)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a 32-bit signed integer. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override int GetInt32(int ordinal) => (int)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as a 64-bit signed integer. - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override long GetInt64(int ordinal) => (long)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the name of the column, given the zero-based column ordinal. - /// - /// The zero-based column ordinal. - /// The name of the specified column. - public override string GetName(int ordinal) => m_PropertyList[ordinal].Name; - - /// - /// Gets the column ordinal given the name of the column. - /// - /// The name of the column. - /// The zero-based column ordinal. - public override int GetOrdinal(string name) => m_PropertyLookup[name]; - - /// - /// Returns a that describes the column metadata of the . - /// - /// A that describes the column metadata. - public override DataTable GetSchemaTable() => m_Schema; - - /// - /// Gets the value of the specified column as an instance of . - /// - /// The zero-based column ordinal. - /// The value of the specified column. - public override string GetString(int ordinal) => (string)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); - - /// - /// Gets the value of the specified column as an instance of . - /// - /// The zero-based column ordinal. - /// The value of the specified column. + return m_Source; + } + + /// + /// Gets the data type of the specified column. + /// + /// The zero-based column ordinal. + /// The data type of the specified column. + public override Type GetFieldType(int ordinal) => m_PropertyList[ordinal].PropertyType; + + /// + /// Gets the value of the specified column as a single-precision floating point number. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override float GetFloat(int ordinal) => (float)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a globally-unique identifier (GUID). + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override Guid GetGuid(int ordinal) => (Guid)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a 16-bit signed integer. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override short GetInt16(int ordinal) => (short)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a 32-bit signed integer. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override int GetInt32(int ordinal) => (int)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as a 64-bit signed integer. + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override long GetInt64(int ordinal) => (long)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the name of the column, given the zero-based column ordinal. + /// + /// The zero-based column ordinal. + /// The name of the specified column. + public override string GetName(int ordinal) => m_PropertyList[ordinal].Name; + + /// + /// Gets the column ordinal given the name of the column. + /// + /// The name of the column. + /// The zero-based column ordinal. + public override int GetOrdinal(string name) => m_PropertyLookup[name]; + + /// + /// Returns a that describes the column metadata of the . + /// + /// A that describes the column metadata. + public override DataTable GetSchemaTable() => m_Schema; + + /// + /// Gets the value of the specified column as an instance of . + /// + /// The zero-based column ordinal. + /// The value of the specified column. + public override string GetString(int ordinal) => (string)(this[ordinal] ?? throw new InvalidOperationException($"Value in ordinal {ordinal} is null. Use IsDBNull before calling this method.")); + + /// + /// Gets the value of the specified column as an instance of . + /// + /// The zero-based column ordinal. + /// The value of the specified column. #pragma warning disable CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes). - public override object? GetValue(int ordinal) => this[ordinal]; + + public override object? GetValue(int ordinal) => this[ordinal]; + #pragma warning restore CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes). - /// - /// Populates an array of objects with the column values of the current row. - /// - /// An array of into which to copy the attribute columns. - /// The number of instances of in the array. - public override int GetValues(object[] values) - { - var result = new object?[m_PropertyList.Length]; - for (var i = 0; i < m_PropertyList.Length; i++) - result[i] = this[i]; - return m_PropertyList.Length; - } + /// + /// Populates an array of objects with the column values of the current row. + /// + /// An array of into which to copy the attribute columns. + /// The number of instances of in the array. + public override int GetValues(object[] values) + { + var result = new object?[m_PropertyList.Length]; + for (var i = 0; i < m_PropertyList.Length; i++) + result[i] = this[i]; + return m_PropertyList.Length; + } - /// - /// Gets a value that indicates whether the column contains nonexistent or missing values. - /// - /// The zero-based column ordinal. - /// true if the specified column is equivalent to ; otherwise false. - public override bool IsDBNull(int ordinal) => this[ordinal] == null; - - /// - /// Advances the reader to the next result when reading the results of a batch of statements. - /// - /// true if there are more result sets; otherwise false. - public override bool NextResult() => false; - - /// - /// Advances the reader to the next record in a result set. - /// - /// true if there are more rows; otherwise false. - public override bool Read() - { - if (m_Source == null) - throw new ObjectDisposedException(nameof(ObjectDataReader)); + /// + /// Gets a value that indicates whether the column contains nonexistent or missing values. + /// + /// The zero-based column ordinal. + /// true if the specified column is equivalent to ; otherwise false. + public override bool IsDBNull(int ordinal) => this[ordinal] == null; - return m_Source.MoveNext(); - } + /// + /// Advances the reader to the next result when reading the results of a batch of statements. + /// + /// true if there are more result sets; otherwise false. + public override bool NextResult() => false; - /// - /// Releases the managed resources used by the and optionally releases the unmanaged resources. - /// - /// true to release managed and unmanaged resources; false to release only unmanaged resources. - protected override void Dispose(bool disposing) - { - if (disposing && m_Source != null) - { - m_Source.Dispose(); - m_Source = null; - } + /// + /// Advances the reader to the next record in a result set. + /// + /// true if there are more rows; otherwise false. + public override bool Read() + { + if (m_Source == null) + throw new ObjectDisposedException(nameof(ObjectDataReader)); + + return m_Source.MoveNext(); + } - base.Dispose(disposing); + /// + /// Releases the managed resources used by the and optionally releases the unmanaged resources. + /// + /// true to release managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + if (disposing && m_Source != null) + { + m_Source.Dispose(); + m_Source = null; } - [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] - [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - static ObjectDataReaderMetadata BuildStructure(string targetName, IReadOnlyList columns, bool allColumnsRequired, OperationTypes operationType) + base.Dispose(disposing); + } + + [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + [SuppressMessage("Microsoft.Globalization", "CA1306:SetLocaleForDataTypes")] + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + static ObjectDataReaderMetadata BuildStructure(string targetName, IReadOnlyList columns, bool allColumnsRequired, OperationTypes operationType) + { + var propertyList = MetadataCache.GetMetadata(typeof(TObject)).Properties.Where(p => p.CanRead && p.MappedColumnName != null).ToList(); + bool checkIgnoreOnInsert = operationType == OperationTypes.Insert; + bool checkIgnoreOnUpdate = operationType == OperationTypes.Update; + + var dtSchema = new DataTable(); + dtSchema.Columns.Add("ColumnName", typeof(string)); + dtSchema.Columns.Add("ColumnOrdinal", typeof(int)); + dtSchema.Columns.Add("ColumnSize", typeof(int)); + dtSchema.Columns.Add("NumericPrecision", typeof(short)); + dtSchema.Columns.Add("NumericScale", typeof(short)); + dtSchema.Columns.Add("DataType", typeof(Type)); + dtSchema.Columns.Add("ProviderType", typeof(int)); + dtSchema.Columns.Add("IsLong", typeof(bool)); + dtSchema.Columns.Add("AllowDBNull", typeof(bool)); + dtSchema.Columns.Add("IsReadOnly", typeof(bool)); + dtSchema.Columns.Add("IsRowVersion", typeof(bool)); + dtSchema.Columns.Add("IsUnique", typeof(bool)); + dtSchema.Columns.Add("IsKey", typeof(bool)); + dtSchema.Columns.Add("IsAutoIncrement", typeof(bool)); + dtSchema.Columns.Add("BaseCatalogName", typeof(string)); + dtSchema.Columns.Add("BaseSchemaName", typeof(string)); + dtSchema.Columns.Add("BaseTableName", typeof(string)); + dtSchema.Columns.Add("BaseColumnName", typeof(string)); + dtSchema.Columns.Add("AutoIncrementSeed", typeof(long)); + dtSchema.Columns.Add("AutoIncrementStep", typeof(long)); + dtSchema.Columns.Add("DefaultValue", typeof(object)); + dtSchema.Columns.Add("Expression", typeof(string)); + dtSchema.Columns.Add("ColumnMapping", typeof(MappingType)); + dtSchema.Columns.Add("BaseTableNamespace", typeof(string)); + dtSchema.Columns.Add("BaseColumnNamespace", typeof(string)); + + var ordinal = 0; + var realPropertyList = new List(columns.Count); + foreach (var column in columns) { - var propertyList = MetadataCache.GetMetadata(typeof(TObject)).Properties.Where(p => p.CanRead && p.MappedColumnName != null).ToList(); - bool checkIgnoreOnInsert = operationType == OperationTypes.Insert; - bool checkIgnoreOnUpdate = operationType == OperationTypes.Update; - - var dtSchema = new DataTable(); - dtSchema.Columns.Add("ColumnName", typeof(string)); - dtSchema.Columns.Add("ColumnOrdinal", typeof(int)); - dtSchema.Columns.Add("ColumnSize", typeof(int)); - dtSchema.Columns.Add("NumericPrecision", typeof(short)); - dtSchema.Columns.Add("NumericScale", typeof(short)); - dtSchema.Columns.Add("DataType", typeof(Type)); - dtSchema.Columns.Add("ProviderType", typeof(int)); - dtSchema.Columns.Add("IsLong", typeof(bool)); - dtSchema.Columns.Add("AllowDBNull", typeof(bool)); - dtSchema.Columns.Add("IsReadOnly", typeof(bool)); - dtSchema.Columns.Add("IsRowVersion", typeof(bool)); - dtSchema.Columns.Add("IsUnique", typeof(bool)); - dtSchema.Columns.Add("IsKey", typeof(bool)); - dtSchema.Columns.Add("IsAutoIncrement", typeof(bool)); - dtSchema.Columns.Add("BaseCatalogName", typeof(string)); - dtSchema.Columns.Add("BaseSchemaName", typeof(string)); - dtSchema.Columns.Add("BaseTableName", typeof(string)); - dtSchema.Columns.Add("BaseColumnName", typeof(string)); - dtSchema.Columns.Add("AutoIncrementSeed", typeof(long)); - dtSchema.Columns.Add("AutoIncrementStep", typeof(long)); - dtSchema.Columns.Add("DefaultValue", typeof(object)); - dtSchema.Columns.Add("Expression", typeof(string)); - dtSchema.Columns.Add("ColumnMapping", typeof(MappingType)); - dtSchema.Columns.Add("BaseTableNamespace", typeof(string)); - dtSchema.Columns.Add("BaseColumnNamespace", typeof(string)); - - var ordinal = 0; - var realPropertyList = new List(columns.Count); - foreach (var column in columns) + PropertyMetadata? property = null; + foreach (var item in propertyList) { - PropertyMetadata? property = null; - foreach (var item in propertyList) + if (column.ClrName.Equals(item.MappedColumnName, StringComparison.OrdinalIgnoreCase) || column.SqlName.Equals(item.MappedColumnName, StringComparison.OrdinalIgnoreCase)) { - if (column.ClrName.Equals(item.MappedColumnName, StringComparison.OrdinalIgnoreCase) || column.SqlName.Equals(item.MappedColumnName, StringComparison.OrdinalIgnoreCase)) - { - if (checkIgnoreOnInsert && item.IgnoreOnInsert) - continue; //look for another match + if (checkIgnoreOnInsert && item.IgnoreOnInsert) + continue; //look for another match - if (checkIgnoreOnUpdate && item.IgnoreOnUpdate) - continue; //look for another match + if (checkIgnoreOnUpdate && item.IgnoreOnUpdate) + continue; //look for another match - property = item; - break; - } + property = item; + break; } + } - if (property == null) - { - if (allColumnsRequired) - throw new MappingException($"Could not find a property on {typeof(TObject).Name} that can be mapped to column {column.SqlName} on {targetName}"); - else - continue; //tables don't need every column - } - - realPropertyList.Add(property); - - var row = dtSchema.NewRow(); - row["ColumnName"] = column.SqlName; - row["ColumnOrdinal"] = ordinal++; - row["ColumnSize"] = -1; - - //this is probably wrong, but we don't have a good way to map from DbType to CLR types. - if (property.PropertyType.Name == "Nullable`1" && property.PropertyType.IsGenericType) - { - row["DataType"] = property.PropertyType.GenericTypeArguments[0]; - } + if (property == null) + { + if (allColumnsRequired) + throw new MappingException($"Could not find a property on {typeof(TObject).Name} that can be mapped to column {column.SqlName} on {targetName}"); else - { - row["DataType"] = property.PropertyType; - } - row["IsLong"] = false; - row["AllowDBNull"] = true; - row["IsReadOnly"] = false; - row["IsRowVersion"] = false; - row["IsUnique"] = false; - row["IsKey"] = false; - row["IsAutoIncrement"] = false; - row["BaseTableName"] = null; - row["BaseColumnName"] = column.SqlName; - row["AutoIncrementSeed"] = 0; - row["AutoIncrementStep"] = 1; - row["ColumnMapping"] = 1; - row["BaseTableNamespace"] = null; - row["BaseColumnNamespace"] = null; - dtSchema.Rows.Add(row); + continue; //tables don't need every column } - return new ObjectDataReaderMetadata(dtSchema, realPropertyList.ToImmutableArray(), realPropertyList.Select((p, x) => new { Index = x, Property = p }).ToImmutableDictionary(px => px.Property.Name, px => px.Index, StringComparer.OrdinalIgnoreCase)); - } + realPropertyList.Add(property); - class ObjectDataReaderMetadata - { - public ObjectDataReaderMetadata(DataTable schema, ImmutableArray properties, ImmutableDictionary propertyLookup) + var row = dtSchema.NewRow(); + row["ColumnName"] = column.SqlName; + row["ColumnOrdinal"] = ordinal++; + row["ColumnSize"] = -1; + + //this is probably wrong, but we don't have a good way to map from DbType to CLR types. + if (property.PropertyType.Name == "Nullable`1" && property.PropertyType.IsGenericType) { - Schema = schema; - Properties = properties; - PropertyLookup = propertyLookup; + row["DataType"] = property.PropertyType.GenericTypeArguments[0]; } + else + { + row["DataType"] = property.PropertyType; + } + row["IsLong"] = false; + row["AllowDBNull"] = true; + row["IsReadOnly"] = false; + row["IsRowVersion"] = false; + row["IsUnique"] = false; + row["IsKey"] = false; + row["IsAutoIncrement"] = false; + row["BaseTableName"] = null; + row["BaseColumnName"] = column.SqlName; + row["AutoIncrementSeed"] = 0; + row["AutoIncrementStep"] = 1; + row["ColumnMapping"] = 1; + row["BaseTableNamespace"] = null; + row["BaseColumnNamespace"] = null; + dtSchema.Rows.Add(row); + } - public ImmutableArray Properties { get; } - public ImmutableDictionary PropertyLookup { get; } - public DataTable Schema { get; } + return new ObjectDataReaderMetadata(dtSchema, realPropertyList.ToImmutableArray(), realPropertyList.Select((p, x) => new { Index = x, Property = p }).ToImmutableDictionary(px => px.Property.Name, px => px.Index, StringComparer.OrdinalIgnoreCase)); + } + + class ObjectDataReaderMetadata + { + public ObjectDataReaderMetadata(DataTable schema, ImmutableArray properties, ImmutableDictionary propertyLookup) + { + Schema = schema; + Properties = properties; + PropertyLookup = propertyLookup; } + + public ImmutableArray Properties { get; } + public ImmutableDictionary PropertyLookup { get; } + public DataTable Schema { get; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Row.cs b/Tortuga.Chain/Tortuga.Chain.Core/Row.cs index dcf025ef6..a12adb55f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Row.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Row.cs @@ -1,78 +1,77 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// A lightweight row expressed as a dictionary. +/// +/// +[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] +public sealed class Row : IReadOnlyDictionary { + readonly Dictionary m_Contents; + /// - /// A lightweight row expressed as a dictionary. + /// Initializes a new instance of the class. /// - /// - [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] - public sealed class Row : IReadOnlyDictionary + /// The contents. + internal Row(Dictionary contents) { - readonly Dictionary m_Contents; - - /// - /// Initializes a new instance of the class. - /// - /// The contents. - internal Row(Dictionary contents) - { - if (contents == null || contents.Count == 0) - throw new ArgumentException($"{nameof(contents)} is null or empty.", nameof(contents)); + if (contents == null || contents.Count == 0) + throw new ArgumentException($"{nameof(contents)} is null or empty.", nameof(contents)); - m_Contents = contents; - } + m_Contents = contents; + } - /// - /// Gets the number of elements in the collection. - /// - public int Count => m_Contents.Count; + /// + /// Gets the number of elements in the collection. + /// + public int Count => m_Contents.Count; - /// - /// Gets an enumerable collection that contains the keys in the read-only dictionary. - /// - public IEnumerable Keys => m_Contents.Keys; + /// + /// Gets an enumerable collection that contains the keys in the read-only dictionary. + /// + public IEnumerable Keys => m_Contents.Keys; - /// - /// Gets an enumerable collection that contains the values in the read-only dictionary. - /// - public IEnumerable Values => m_Contents.Values; + /// + /// Gets an enumerable collection that contains the values in the read-only dictionary. + /// + public IEnumerable Values => m_Contents.Values; - /// - /// Gets the with the specified key. - /// - /// - /// The . - /// - /// The key. - /// - public object? this[string key] => m_Contents[key]; + /// + /// Gets the with the specified key. + /// + /// + /// The . + /// + /// The key. + /// + public object? this[string key] => m_Contents[key]; - /// - /// Determines whether the read-only dictionary contains an element that has the specified key. - /// - /// The key to locate. - /// - /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. - /// - public bool ContainsKey(string key) => m_Contents.ContainsKey(key); + /// + /// Determines whether the read-only dictionary contains an element that has the specified key. + /// + /// The key to locate. + /// + /// true if the read-only dictionary contains an element that has the specified key; otherwise, false. + /// + public bool ContainsKey(string key) => m_Contents.ContainsKey(key); - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator> GetEnumerator() => m_Contents.GetEnumerator(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator> GetEnumerator() => m_Contents.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)m_Contents).GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)m_Contents).GetEnumerator(); - /// - /// Gets the value that is associated with the specified key. - /// - /// The key to locate. - /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - public bool TryGetValue(string key, out object? value) => m_Contents.TryGetValue(key, out value); - } + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. + public bool TryGetValue(string key, out object? value) => m_Contents.TryGetValue(key, out value); } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/RowCollection.cs b/Tortuga.Chain/Tortuga.Chain.Core/RowCollection.cs index 917a9026b..bf35e9515 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/RowCollection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/RowCollection.cs @@ -1,19 +1,18 @@ using System.Collections.ObjectModel; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Collection of row objects +/// +public sealed class RowCollection : ReadOnlyCollection { /// - /// Collection of row objects + /// Initializes a new instance of the class. /// - public sealed class RowCollection : ReadOnlyCollection + /// The list. + public RowCollection(IList list) + : base(list) { - /// - /// Initializes a new instance of the class. - /// - /// The list. - public RowCollection(IList list) - : base(list) - { - } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/RowOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/RowOptions.cs index 05dcc2a50..88baeee51 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/RowOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/RowOptions.cs @@ -1,44 +1,43 @@ using System.ComponentModel; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Controls what happens when the wrong number of rows are returned. +/// +[Flags] +public enum RowOptions { /// - /// Controls what happens when the wrong number of rows are returned. + /// Use the default behavior for the materializer. /// - [Flags] - public enum RowOptions - { - /// - /// Use the default behavior for the materializer. - /// - /// - None = 0, + /// + None = 0, - /// - /// An error will not be raised if no rows are returned. - /// - /// - [Obsolete("This option is no longer supported. Use the XxxOrNull version of the function instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - AllowEmptyResults = 1, + /// + /// An error will not be raised if no rows are returned. + /// + /// + [Obsolete("This option is no longer supported. Use the XxxOrNull version of the function instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + AllowEmptyResults = 1, - /// - /// An error will not be raised if extra rows are returned. The extras will be discarded. - /// - /// - /// If a class has more than one constructor, the default constructor will be used. - DiscardExtraRows = 2, + /// + /// An error will not be raised if extra rows are returned. The extras will be discarded. + /// + /// + /// If a class has more than one constructor, the default constructor will be used. + DiscardExtraRows = 2, - /// - /// Infer which non-default constructor to use. When this option is chosen, individual properties will not be set. - /// - /// This will throw an error unless there is exactly one public, non-default constructor. - InferConstructor = 8, + /// + /// Infer which non-default constructor to use. When this option is chosen, individual properties will not be set. + /// + /// This will throw an error unless there is exactly one public, non-default constructor. + InferConstructor = 8, - /// - /// An error will be raised if no rows are returned - /// - /// - PreventEmptyResults = 16, - } + /// + /// An error will be raised if no rows are returned + /// + /// + PreventEmptyResults = 16, } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/SortDirection.cs b/Tortuga.Chain/Tortuga.Chain.Core/SortDirection.cs index bff48d39d..854130e5f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/SortDirection.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/SortDirection.cs @@ -1,21 +1,20 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Used to indicate the sort direction +/// +[SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32")] +public enum SortDirection : byte { /// - /// Used to indicate the sort direction + /// Ascending /// - [SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32")] - public enum SortDirection : byte - { - /// - /// Ascending - /// - Ascending = 0, + Ascending = 0, - /// - /// Descending - /// - Descending = 1 - } + /// + /// Descending + /// + Descending = 1 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/SortExpression.cs b/Tortuga.Chain/Tortuga.Chain.Core/SortExpression.cs index 92ae5e32d..1be69d316 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/SortExpression.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/SortExpression.cs @@ -1,120 +1,119 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Sort expressions are used for From and FromFunction command builders. +/// +/// You can implicitly convert strings into sort expressions. +public struct SortExpression : IEquatable { /// - /// Sort expressions are used for From and FromFunction command builders. + /// Initializes a new instance of the class. /// - /// You can implicitly convert strings into sort expressions. - public struct SortExpression : IEquatable + /// Name of the column to be sorted by. + /// if set to true [descending]. + /// + public SortExpression(string columnName, SortDirection descending) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the column to be sorted by. - /// if set to true [descending]. - /// - public SortExpression(string columnName, SortDirection descending) - { - if (string.IsNullOrWhiteSpace(columnName)) - throw new ArgumentException($"{nameof(columnName)} is null or empty.", nameof(columnName)); + if (string.IsNullOrWhiteSpace(columnName)) + throw new ArgumentException($"{nameof(columnName)} is null or empty.", nameof(columnName)); - ColumnName = columnName; - Direction = descending; - } + ColumnName = columnName; + Direction = descending; + } - /// - /// Initializes a new instance of the class. - /// - /// Name of the column to be sorted by. - /// - public SortExpression(string columnName) - { - if (string.IsNullOrWhiteSpace(columnName)) - throw new ArgumentException($"{nameof(columnName)} is null or empty.", nameof(columnName)); + /// + /// Initializes a new instance of the class. + /// + /// Name of the column to be sorted by. + /// + public SortExpression(string columnName) + { + if (string.IsNullOrWhiteSpace(columnName)) + throw new ArgumentException($"{nameof(columnName)} is null or empty.", nameof(columnName)); - ColumnName = columnName; - Direction = SortDirection.Ascending; - } + ColumnName = columnName; + Direction = SortDirection.Ascending; + } - /// - /// Gets the name of the column to be sorted by. - /// - /// - /// The name of the column. - /// - public string? ColumnName { get; } + /// + /// Gets the name of the column to be sorted by. + /// + /// + /// The name of the column. + /// + public string? ColumnName { get; } - /// - /// Gets a value indicating whether this is descending. - /// - /// - /// true if descending; otherwise, false. - /// - public SortDirection Direction { get; } + /// + /// Gets a value indicating whether this is descending. + /// + /// + /// true if descending; otherwise, false. + /// + public SortDirection Direction { get; } - /// - /// Perform an implicit conversion from to with Ascending as the sort direction. - /// - /// The columnName - /// - /// The result of the conversion. - /// - [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")] - public static implicit operator SortExpression(string columnName) => new SortExpression(columnName); + /// + /// Perform an implicit conversion from to with Ascending as the sort direction. + /// + /// The columnName + /// + /// The result of the conversion. + /// + [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")] + public static implicit operator SortExpression(string columnName) => new SortExpression(columnName); - /// - /// Implements the != operator. - /// - /// The left. - /// The right. - /// The result of the operator. - public static bool operator !=(SortExpression left, SortExpression right) - { - return !(left == right); - } + /// + /// Implements the != operator. + /// + /// The left. + /// The right. + /// The result of the operator. + public static bool operator !=(SortExpression left, SortExpression right) + { + return !(left == right); + } - /// - /// Implements the == operator. - /// - /// The left. - /// The right. - /// The result of the operator. - public static bool operator ==(SortExpression left, SortExpression right) - { - return left.Equals(right); - } + /// + /// Implements the == operator. + /// + /// The left. + /// The right. + /// The result of the operator. + public static bool operator ==(SortExpression left, SortExpression right) + { + return left.Equals(right); + } - /// - /// Indicates whether the current object is equal to another object of the same type. - /// - /// An object to compare with this object. - /// if the current object is equal to the parameter; otherwise, . - public bool Equals(SortExpression other) - { - return string.Equals(ColumnName, other.ColumnName, StringComparison.OrdinalIgnoreCase) && Direction == other.Direction; - } + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// An object to compare with this object. + /// if the current object is equal to the parameter; otherwise, . + public bool Equals(SortExpression other) + { + return string.Equals(ColumnName, other.ColumnName, StringComparison.OrdinalIgnoreCase) && Direction == other.Direction; + } - /// - /// Determines whether the specified is equal to this instance. - /// - /// The object to compare with the current instance. - /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals(object? obj) - { - var temp = obj as SortExpression?; - if (temp == null) - return false; - return Equals(temp.Value); - } + /// + /// Determines whether the specified is equal to this instance. + /// + /// The object to compare with the current instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object? obj) + { + var temp = obj as SortExpression?; + if (temp == null) + return false; + return Equals(temp.Value); + } - /// - /// Returns a hash code for this instance. - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - public override int GetHashCode() - { - return (ColumnName?.GetHashCode(StringComparison.OrdinalIgnoreCase) ?? 0) + (int)Direction; - } + /// + /// Returns a hash code for this instance. + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() + { + return (ColumnName?.GetHashCode(StringComparison.OrdinalIgnoreCase) ?? 0) + (int)Direction; } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Table.cs b/Tortuga.Chain/Tortuga.Chain.Core/Table.cs index 0f9c031ec..632873c1e 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Table.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/Table.cs @@ -5,299 +5,350 @@ using System.Reflection; using Tortuga.Anchor.Metadata; using Tortuga.Chain.Materializers; - -namespace Tortuga.Chain +using Tortuga.Chain.Metadata; + +namespace Tortuga.Chain; + +/// +/// A light-weight object to hold tabular data +/// +/// +/// This is much faster than a DataTable, but lacks most of its features. +/// +[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] +public sealed class Table { + readonly ReadOnlyCollection m_Columns; + readonly ReadOnlyDictionary m_ColumnTypes; + readonly MaterializerTypeConverter m_Converter; + readonly RowCollection m_Rows; + /// - /// A light-weight object to hold tabular data + /// Creates a new NamedTable from an IDataReader /// - /// - /// This is much faster than a DataTable, but lacks most of its features. - /// - [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] - public sealed class Table + /// Name of the table. + /// The source. + /// The type converter. + public Table(string tableName, IDataReader source, MaterializerTypeConverter converter) + : this(source, converter) { - readonly ReadOnlyCollection m_Columns; - readonly ReadOnlyDictionary m_ColumnTypes; - readonly RowCollection m_Rows; - - /// - /// Creates a new NamedTable from an IDataReader - /// - /// Name of the table. - /// The source. - public Table(string tableName, IDataReader source) - : this(source) - { - TableName = tableName; - } + TableName = tableName; + } - /// - /// Creates a new NamedTable from an IDataReader - /// - /// Name of the table. - /// The source. - public Table(string tableName, DbDataReader source) - : this(source) - { - TableName = tableName; - } + /// + /// Creates a new NamedTable from an IDataReader + /// + /// Name of the table. + /// The source. + /// The type converter. + public Table(string tableName, DbDataReader source, MaterializerTypeConverter converter) + : this(source, converter) + { + TableName = tableName; + } + + /// + /// Creates a new Table from an IDataReader + /// + /// The source. + /// nameof(s - rce), "source is + /// No columns were returned - source + /// The type converter. + public Table(DbDataReader source, MaterializerTypeConverter converter) + { + if (source == null) + throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); + if (source.FieldCount == 0) + throw new ArgumentException("No columns were returned", nameof(source)); - /// - /// Creates a new Table from an IDataReader - /// - /// The source. - /// nameof(s - rce), "source is - /// No columns were returned - source - public Table(DbDataReader source) + m_Converter = converter ?? new(); + + TableName = ""; + + var cols = new List(source.FieldCount); + var colTypes = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); + for (var i = 0; i < source.FieldCount; i++) { - if (source == null) - throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); - if (source.FieldCount == 0) - throw new ArgumentException("No columns were returned", nameof(source)); + cols.Add(source.GetName(i)); + colTypes.Add(source.GetName(i), source.GetFieldType(i)); + } + m_Columns = new ReadOnlyCollection(cols); + m_ColumnTypes = new ReadOnlyDictionary(colTypes); - TableName = ""; + var rows = new Collection(); - var cols = new List(source.FieldCount); - var colTypes = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); + while (source.Read()) + { + var row = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); for (var i = 0; i < source.FieldCount; i++) { - cols.Add(source.GetName(i)); - colTypes.Add(source.GetName(i), source.GetFieldType(i)); + object? temp = source[i]; + if (temp == DBNull.Value) + temp = null; + + row.Add(source.GetName(i), temp); } - m_Columns = new ReadOnlyCollection(cols); - m_ColumnTypes = new ReadOnlyDictionary(colTypes); - var rows = new Collection(); + rows.Add(new Row(row)); + } - while (source.Read()) - { - var row = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); - for (var i = 0; i < source.FieldCount; i++) - { - object? temp = source[i]; - if (temp == DBNull.Value) - temp = null; + m_Rows = new RowCollection(rows); + } - row.Add(source.GetName(i), temp); - } + /// + /// Creates a new Table from an IDataReader + /// + /// + /// The type converter. + public Table(IDataReader source, MaterializerTypeConverter converter) + { + if (source == null) + throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); + if (source.FieldCount == 0) + throw new ArgumentException("No columns were returned", nameof(source)); - rows.Add(new Row(row)); - } + m_Converter = converter ?? new(); - m_Rows = new RowCollection(rows); - } + TableName = ""; - /// - /// Creates a new Table from an IDataReader - /// - /// - public Table(IDataReader source) + var cols = new List(source.FieldCount); + var colTypes = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); + for (var i = 0; i < source.FieldCount; i++) { - if (source == null) - throw new ArgumentNullException(nameof(source), $"{nameof(source)} is null."); - if (source.FieldCount == 0) - throw new ArgumentException("No columns were returned", nameof(source)); + cols.Add(source.GetName(i)); + colTypes.Add(source.GetName(i), source.GetFieldType(i)); + } + m_Columns = new ReadOnlyCollection(cols); + m_ColumnTypes = new ReadOnlyDictionary(colTypes); - TableName = ""; + var rows = new Collection(); - var cols = new List(source.FieldCount); - var colTypes = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); + while (source.Read()) + { + var row = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); for (var i = 0; i < source.FieldCount; i++) { - cols.Add(source.GetName(i)); - colTypes.Add(source.GetName(i), source.GetFieldType(i)); + object? temp = source[i]; + if (temp == DBNull.Value) + temp = null; + + row.Add(source.GetName(i), temp); } - m_Columns = new ReadOnlyCollection(cols); - m_ColumnTypes = new ReadOnlyDictionary(colTypes); - var rows = new Collection(); + rows.Add(new Row(row)); + } - while (source.Read()) - { - var row = new Dictionary(source.FieldCount, StringComparer.OrdinalIgnoreCase); - for (var i = 0; i < source.FieldCount; i++) - { - object? temp = source[i]; - if (temp == DBNull.Value) - temp = null; + m_Rows = new RowCollection(rows); + } - row.Add(source.GetName(i), temp); - } + /// + /// Creates a new NamedTable from an IDataReader + /// + /// Name of the table. + /// The source. + [Obsolete("Pass DataSource.DatabaseMetadata.Converter to the constructor")] + public Table(string tableName, IDataReader source) + : this(tableName, source, new()) + { + } - rows.Add(new Row(row)); - } + /// + /// Creates a new NamedTable from an IDataReader + /// + /// Name of the table. + /// The source. + [Obsolete("Pass DataSource.DatabaseMetadata.Converter to the constructor")] + public Table(string tableName, DbDataReader source) + : this(tableName, source, new()) + { + } - m_Rows = new RowCollection(rows); - } + /// + /// Creates a new Table from an IDataReader + /// + /// The source. + /// nameof(s - rce), "source is + /// No columns were returned - source + [Obsolete("Pass DataSource.DatabaseMetadata.Converter to the constructor")] + public Table(DbDataReader source) : this(source, new()) + { + } + + /// + /// Creates a new Table from an IDataReader + /// + /// + [Obsolete("Pass DataSource.DatabaseMetadata.Converter to the constructor")] + public Table(IDataReader source) : this(source, new()) + { + } + + /// + /// List of column names in their original order. + /// + public IReadOnlyList ColumnNames => m_Columns; + + /// + /// List of columns and their types. + /// + public IReadOnlyDictionary ColumnTypeMap => m_ColumnTypes; + + /// + /// Gets the rows. + /// + /// The rows. + public IReadOnlyList Rows => m_Rows; + + /// + /// Gets the name of the table. + /// + /// The name of the table. + public string TableName { get; set; } - /// - /// List of column names in their original order. - /// - public IReadOnlyList ColumnNames => m_Columns; - - /// - /// List of columns and their types. - /// - public IReadOnlyDictionary ColumnTypeMap => m_ColumnTypes; - - /// - /// Gets the rows. - /// - /// The rows. - public IReadOnlyList Rows => m_Rows; - - /// - /// Gets the name of the table. - /// - /// The name of the table. - public string TableName { get; set; } - - /// - /// Converts the table into an enumeration of objects of the indicated type. - /// - /// Desired object type - public IEnumerable ToObjects() where T : class, new() + /// + /// Converts the table into an enumeration of objects of the indicated type. + /// + /// Desired object type + public IEnumerable ToObjects() where T : class, new() + { + foreach (var row in Rows) { - foreach (var row in Rows) - { - var item = new T(); - MaterializerUtilities.PopulateComplexObject(row, item, null); + var item = new T(); + MaterializerUtilities.PopulateComplexObject(row, item, null, m_Converter); - //Change tracking objects shouldn't be materialized as unchanged. - var tracking = item as IChangeTracking; - tracking?.AcceptChanges(); + //Change tracking objects shouldn't be materialized as unchanged. + var tracking = item as IChangeTracking; + tracking?.AcceptChanges(); - yield return item; - } + yield return item; } + } - /// - /// Converts the table into an enumeration of objects of the indicated type using the indicated constructor. - /// - /// Desired object type - /// The constructor signature. - /// IEnumerable<T>. - public IEnumerable ToObjects(IReadOnlyList? constructorSignature) + /// + /// Converts the table into an enumeration of objects of the indicated type using the indicated constructor. + /// + /// Desired object type + /// The constructor signature. + /// IEnumerable<T>. + public IEnumerable ToObjects(IReadOnlyList? constructorSignature) + { + if (constructorSignature == null) { - if (constructorSignature == null) - { - var methodType = GetType().GetMethod("ToObjects", Array.Empty())!; - var genericMethod = methodType.MakeGenericMethod(typeof(T)); - return (IEnumerable)genericMethod.Invoke(this, null)!; - } - else - return ToObjects_Core(constructorSignature); + var methodType = GetType().GetMethod("ToObjects", Array.Empty())!; + var genericMethod = methodType.MakeGenericMethod(typeof(T)); + return (IEnumerable)genericMethod.Invoke(this, null)!; } + else + return ToObjects_Core(constructorSignature); + } - /// - /// Converts the table into an enumeration of objects of the indicated type using the indicated constructor. - /// - /// Desired object type - /// The constructor. - /// IEnumerable<T>. - public IEnumerable ToObjects(ConstructorMetadata? constructor) + /// + /// Converts the table into an enumeration of objects of the indicated type using the indicated constructor. + /// + /// Desired object type + /// The constructor. + /// IEnumerable<T>. + public IEnumerable ToObjects(ConstructorMetadata? constructor) + { + if (constructor == null) { - if (constructor == null) - { - var methodType = GetType().GetMethod("ToObjects", Array.Empty())!; - var genericMethod = methodType.MakeGenericMethod(typeof(T)); - return (IEnumerable)genericMethod.Invoke(this, null)!; - } - else - return ToObjects_Core(constructor); + var methodType = GetType().GetMethod("ToObjects", Array.Empty())!; + var genericMethod = methodType.MakeGenericMethod(typeof(T)); + return (IEnumerable)genericMethod.Invoke(this, null)!; } + else + return ToObjects_Core(constructor); + } - internal IEnumerable ToObjects_Core(IReadOnlyList constructorSignature) + internal IEnumerable ToObjects_Core(IReadOnlyList constructorSignature) + { + var desiredType = typeof(T); + var constructor = MetadataCache.GetMetadata(desiredType).Constructors.Find(constructorSignature); + if (constructor == null) { - var desiredType = typeof(T); - var constructor = MetadataCache.GetMetadata(desiredType).Constructors.Find(constructorSignature); - if (constructor == null) - { - var types = string.Join(", ", constructorSignature.Select(t => t.Name)); - throw new MappingException($"Cannot find a constructor on {desiredType.Name} with the types [{types}]"); - } - return ToObjects_Core(constructor); + var types = string.Join(", ", constructorSignature.Select(t => t.Name)); + throw new MappingException($"Cannot find a constructor on {desiredType.Name} with the types [{types}]"); } + return ToObjects_Core(constructor); + } - internal IEnumerable ToObjects_Core(ConstructorMetadata constructor) + internal IEnumerable ToObjects_Core(ConstructorMetadata constructor) + { + if (constructor == null) + throw new ArgumentNullException(nameof(constructor), $"{nameof(constructor)} is null."); + + var constructorParameters = constructor.ParameterNames; + for (var i = 0; i < constructorParameters.Length; i++) { - if (constructor == null) - throw new ArgumentNullException(nameof(constructor), $"{nameof(constructor)} is null."); + if (!ColumnNames.Any(p => p.Equals(constructorParameters[i], StringComparison.OrdinalIgnoreCase))) + throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); + } - var constructorParameters = constructor.ParameterNames; + foreach (var item in Rows) + { + var parameters = new object?[constructorParameters.Length]; for (var i = 0; i < constructorParameters.Length; i++) { - if (!ColumnNames.Any(p => p.Equals(constructorParameters[i], StringComparison.OrdinalIgnoreCase))) - throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); - } - - foreach (var item in Rows) - { - var parameters = new object?[constructorParameters.Length]; - for (var i = 0; i < constructorParameters.Length; i++) - { - parameters[i] = item[constructorParameters[i]]; - } - var result = constructor.ConstructorInfo.Invoke(parameters); - yield return (T)result; + parameters[i] = item[constructorParameters[i]]; } + var result = constructor.ConstructorInfo.Invoke(parameters); + yield return (T)result; } + } - internal IEnumerable> ToObjectsWithEcho(ConstructorMetadata? constructor) + internal IEnumerable> ToObjectsWithEcho(ConstructorMetadata? constructor) + { + if (constructor == null) { - if (constructor == null) - { - var methodType = GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).Single(m => m.Name == "ToObjectsWithEcho_New"); - var genericMethod = methodType.MakeGenericMethod(typeof(T)); - return (IEnumerable>)genericMethod.Invoke(this, null)!; - } - else - return ToObjectsWithEcho_Core(constructor); + var methodType = GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).Single(m => m.Name == "ToObjectsWithEcho_New"); + var genericMethod = methodType.MakeGenericMethod(typeof(T)); + return (IEnumerable>)genericMethod.Invoke(this, null)!; } + else + return ToObjectsWithEcho_Core(constructor); + } + + internal IEnumerable> ToObjectsWithEcho_Core(ConstructorMetadata constructor) + { + if (constructor == null) + throw new ArgumentNullException(nameof(constructor), $"{nameof(constructor)} is null."); - internal IEnumerable> ToObjectsWithEcho_Core(ConstructorMetadata constructor) + var constructorParameters = constructor.ParameterNames; + for (var i = 0; i < constructorParameters.Length; i++) { - if (constructor == null) - throw new ArgumentNullException(nameof(constructor), $"{nameof(constructor)} is null."); + if (!ColumnNames.Any(p => p.Equals(constructorParameters[i], StringComparison.OrdinalIgnoreCase))) + throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); + } - var constructorParameters = constructor.ParameterNames; + foreach (var item in Rows) + { + var parameters = new object?[constructorParameters.Length]; for (var i = 0; i < constructorParameters.Length; i++) { - if (!ColumnNames.Any(p => p.Equals(constructorParameters[i], StringComparison.OrdinalIgnoreCase))) - throw new MappingException($"Cannot find a column that matches the parameter {constructorParameters[i]}"); - } - - foreach (var item in Rows) - { - var parameters = new object?[constructorParameters.Length]; - for (var i = 0; i < constructorParameters.Length; i++) - { - parameters[i] = item[constructorParameters[i]]; - } - var result = constructor.ConstructorInfo.Invoke(parameters); - yield return new KeyValuePair(item, (T)result); + parameters[i] = item[constructorParameters[i]]; } + var result = constructor.ConstructorInfo.Invoke(parameters); + yield return new KeyValuePair(item, (T)result); } + } - /// - /// Converts the table into an enumeration of objects of the indicated type. - /// - /// Desired object type - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal IEnumerable> ToObjectsWithEcho_New() where T : class, new() + /// + /// Converts the table into an enumeration of objects of the indicated type. + /// + /// Desired object type + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal IEnumerable> ToObjectsWithEcho_New() where T : class, new() + { + foreach (var row in Rows) { - foreach (var row in Rows) - { - var item = new T(); - MaterializerUtilities.PopulateComplexObject(row, item, null); + var item = new T(); + MaterializerUtilities.PopulateComplexObject(row, item, null, m_Converter); - //Change tracking objects shouldn't be materialized as unchanged. - var tracking = item as IChangeTracking; - tracking?.AcceptChanges(); + //Change tracking objects shouldn't be materialized as unchanged. + var tracking = item as IChangeTracking; + tracking?.AcceptChanges(); - yield return new KeyValuePair(row, item); - } + yield return new KeyValuePair(row, item); } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/TableSet.cs b/Tortuga.Chain/Tortuga.Chain.Core/TableSet.cs index bd1dcae7c..83154395f 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/TableSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/TableSet.cs @@ -2,89 +2,91 @@ using System.Collections.ObjectModel; using System.Data.Common; using System.Diagnostics.CodeAnalysis; +using Tortuga.Chain.Metadata; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// A set of named tables. +/// +/// This is much faster than a DataSet, but lacks most of its features. +[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] +public sealed class TableSet : IReadOnlyList
{ + readonly TSKeyedCollection m_Internal = new TSKeyedCollection(); + /// - /// A set of named tables. + /// Initializes a new instance of the class. /// - /// This is much faster than a DataSet, but lacks most of its features. - [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] - public sealed class TableSet : IReadOnlyList
+ /// The data reader used to populate this TableSet. + /// The type converter. + /// Optional list of table names. + /// reader + public TableSet(DbDataReader reader, MaterializerTypeConverter converter, params string[] tableNames) { - readonly TSKeyedCollection m_Internal = new TSKeyedCollection(); + if (reader == null) + throw new ArgumentNullException(nameof(reader), $"{nameof(reader)} is null."); + if (tableNames == null) + tableNames = Array.Empty(); - /// - /// Initializes a new instance of the class. - /// - /// The data reader used to populate this TableSet. - /// Optional list of table names. - public TableSet(DbDataReader reader, params string[] tableNames) + var index = 0; + do { - if (reader == null) - throw new ArgumentNullException(nameof(reader), $"{nameof(reader)} is null."); - if (tableNames == null) - tableNames = Array.Empty(); - - var index = 0; - do - { - var tableName = (index < tableNames.Length) ? tableNames[index] : ("Table " + index); - m_Internal.Add(new Table(tableName, reader)); - index += 1; - } - while (reader.NextResult()); + var tableName = (index < tableNames.Length) ? tableNames[index] : ("Table " + index); + m_Internal.Add(new Table(tableName, reader, converter)); + index += 1; } + while (reader.NextResult()); + } - /// - /// Gets the number of elements in the collection. - /// - public int Count => m_Internal.Count; + /// + /// Gets the number of elements in the collection. + /// + public int Count => m_Internal.Count; - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// - public Table this[int index] => m_Internal[index]; + /// + /// Gets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// + public Table this[int index] => m_Internal[index]; - /// - /// Gets the with the specified key. - /// - /// - /// The . - /// - /// The key. - /// - public Table this[string key] => m_Internal[key]; + /// + /// Gets the with the specified key. + /// + /// + /// The . + /// + /// The key. + /// + public Table this[string key] => m_Internal[key]; - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator
GetEnumerator() => m_Internal.GetEnumerator(); + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator
GetEnumerator() => m_Internal.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => m_Internal.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => m_Internal.GetEnumerator(); - class TSKeyedCollection : KeyedCollection + class TSKeyedCollection : KeyedCollection + { + /// + /// When implemented in a derived class, extracts the key from the specified element. + /// + /// The element from which to extract the key. + /// The key for the specified element. + protected override string GetKeyForItem(Table item) { - /// - /// When implemented in a derived class, extracts the key from the specified element. - /// - /// The element from which to extract the key. - /// The key for the specified element. - protected override string GetKeyForItem(Table item) - { - if (item == null) - throw new ArgumentNullException(nameof(item), $"{nameof(item)} is null."); + if (item == null) + throw new ArgumentNullException(nameof(item), $"{nameof(item)} is null."); - return item.TableName; - } + return item.TableName; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/Tortuga.Chain.Core.csproj b/Tortuga.Chain/Tortuga.Chain.Core/Tortuga.Chain.Core.csproj index 5517b63ff..4fa2f3723 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/Tortuga.Chain.Core.csproj +++ b/Tortuga.Chain/Tortuga.Chain.Core/Tortuga.Chain.Core.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.0 + 4.1.0 MIT diff --git a/Tortuga.Chain/Tortuga.Chain.Core/UnexpectedDataException.cs b/Tortuga.Chain/Tortuga.Chain.Core/UnexpectedDataException.cs index 1ff1c0b7c..47246875b 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/UnexpectedDataException.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/UnexpectedDataException.cs @@ -1,48 +1,47 @@ using System.Runtime.Serialization; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// This exception indicates that unexpected data was returned from the database. +/// +/// This can occur when more rows or columns than expected were returned. +[Serializable] +public class UnexpectedDataException : DataException { /// - /// This exception indicates that unexpected data was returned from the database. + /// Initializes a new instance of the class. /// - /// This can occur when more rows or columns than expected were returned. - [Serializable] - public class UnexpectedDataException : DataException + public UnexpectedDataException() { - /// - /// Initializes a new instance of the class. - /// - public UnexpectedDataException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public UnexpectedDataException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public UnexpectedDataException(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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. - public UnexpectedDataException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// 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. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. + public UnexpectedDataException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The data necessary to serialize or deserialize an object. - /// Description of the source and destination of the specified serialized stream. - protected UnexpectedDataException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The data necessary to serialize or deserialize an object. + /// Description of the source and destination of the specified serialized stream. + protected UnexpectedDataException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/UpdateOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/UpdateOptions.cs index bf0748663..5f0419201 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/UpdateOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/UpdateOptions.cs @@ -1,46 +1,45 @@ using System.ComponentModel; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Controls what happens when performing a model-based update +/// +[Flags] +public enum UpdateOptions { /// - /// Controls what happens when performing a model-based update + /// Update all non-primary key columns using the primary key columns for the where clause. /// - [Flags] - public enum UpdateOptions - { - /// - /// Update all non-primary key columns using the primary key columns for the where clause. - /// - None = 0, + None = 0, - /// - /// Uses the IPropertyChangeTracking interface to only update changed properties. - /// - /// If this flag is set and IPropertyChangeTracking.IsChanged is false, an error will occur. - ChangedPropertiesOnly = 1, + /// + /// Uses the IPropertyChangeTracking interface to only update changed properties. + /// + /// If this flag is set and IPropertyChangeTracking.IsChanged is false, an error will occur. + ChangedPropertiesOnly = 1, - /// - /// Ignore the primary keys on the table and perform the update using the Key attribute on properties to construct the where clause. - /// - /// This is generally used for heap-style tables, though technically heap tables may have primary, non-clustered keys. - UseKeyAttribute = 2, + /// + /// Ignore the primary keys on the table and perform the update using the Key attribute on properties to construct the where clause. + /// + /// This is generally used for heap-style tables, though technically heap tables may have primary, non-clustered keys. + UseKeyAttribute = 2, - /// - /// The return original values instead of the updated values. - /// - /// This has no effect when using the NonQuery materializer. - ReturnOldValues = 4, + /// + /// The return original values instead of the updated values. + /// + /// This has no effect when using the NonQuery materializer. + ReturnOldValues = 4, - /// - /// Perform a soft delete as part of this update operation. - /// - /// This is meant for internal use only. - [EditorBrowsable(EditorBrowsableState.Never)] - SoftDelete = 8, + /// + /// Perform a soft delete as part of this update operation. + /// + /// This is meant for internal use only. + [EditorBrowsable(EditorBrowsableState.Never)] + SoftDelete = 8, - /// - /// The ignore rows affected count. Without this flag, an error will be thrown if the rows affected by the update operation is not one. - /// - IgnoreRowsAffected = 16 - } + /// + /// The ignore rows affected count. Without this flag, an error will be thrown if the rows affected by the update operation is not one. + /// + IgnoreRowsAffected = 16 } diff --git a/Tortuga.Chain/Tortuga.Chain.Core/UpsertOptions.cs b/Tortuga.Chain/Tortuga.Chain.Core/UpsertOptions.cs index 2135a8ab2..1343a4397 100644 --- a/Tortuga.Chain/Tortuga.Chain.Core/UpsertOptions.cs +++ b/Tortuga.Chain/Tortuga.Chain.Core/UpsertOptions.cs @@ -1,35 +1,35 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Controls what happens when performing a model-based insert or update +/// +[Flags] +public enum UpsertOptions { /// - /// Controls what happens when performing a model-based insert or update + /// Update all non-primary key columns using the primary key columns for the where clause. /// - [Flags] - public enum UpsertOptions - { - /// - /// Update all non-primary key columns using the primary key columns for the where clause. - /// - None = 0, + None = 0, - /// - /// Uses the IPropertyChangeTracking interface to only update changed properties. This flag has no effect when performing an insert. - /// - /// If this flag is set and IPropertyChangeTracking.IsChanged is false, an error will occur. - ChangedPropertiesOnly = 1, + /// + /// Uses the IPropertyChangeTracking interface to only update changed properties. This flag has no effect when performing an insert. + /// + /// If this flag is set and IPropertyChangeTracking.IsChanged is false, an error will occur. + ChangedPropertiesOnly = 1, - /// - /// Ignore the primary keys on the table and perform the update using the Key attribute on properties to construct the where clause. - /// - /// This is generally used for heap-style tables, though technically heap tables may have primary, non-clustered keys. - UseKeyAttribute = 2, + /// + /// Ignore the primary keys on the table and perform the update using the Key attribute on properties to construct the where clause. + /// + /// This is generally used for heap-style tables, though technically heap tables may have primary, non-clustered keys. + UseKeyAttribute = 2, - /// - /// Allows overriding identity/auto-number column - /// - /// This may require elevated privileges. This is not supported by all databases. - IdentityInsert = 4, + /// + /// Allows overriding identity/auto-number column + /// + /// This may require elevated privileges. This is not supported by all databases. + IdentityInsert = 4, - /* + /* * Might need this for PostgreSQL /// /// Do not reset the identity/auto-number column after performing an identity insert. @@ -37,5 +37,4 @@ public enum UpsertOptions /// Use this when performing a series of identity inserts to improve performance. Then invoke ResetIdentity on the DataSource. This is a no-op when resetting the identity column is not necessary (Access, SQL Server, SQLite). DoNotResetIdentityColumn = 8 */ - } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql.Tests/Setup.cs b/Tortuga.Chain/Tortuga.Chain.MySql.Tests/Setup.cs index 008fdcdb4..3ba8bcddf 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql.Tests/Setup.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql.Tests/Setup.cs @@ -75,7 +75,9 @@ State CHAR(2) NOT NULL, DeletedFlag boolean NOT NULL DEFAULT FALSE, DeletedDate TIMESTAMP NULL, - DeletedByKey INTEGER NULL + DeletedByKey INTEGER NULL, + BirthDay DATE NULL, + PreferredCallTime TIME NULL ); CREATE TABLE sales.location ( diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index 1b7983226..000000000 --- a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,31 +0,0 @@ -/* -Container class: Tortuga.Chain.MySqlDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.MySql.MySqlDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsTruncateTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsInsertBatchTrait> - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait - Adding trait: Traits.SupportsUpsertTrait - Adding trait: Traits.SupportsInsertBulkTrait - Adding trait: Traits.SupportsScalarFunctionTrait - Adding trait: Traits.SupportsProcedureTrait -Container class: Tortuga.Chain.MySql.MySqlOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.MySql.MySqlTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlDataSourceBase.cs deleted file mode 100644 index 04a4bbd64..000000000 --- a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlDataSourceBase.cs +++ /dev/null @@ -1,1361 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.MySql -{ - partial class MySqlDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsTruncate, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsInsertBatch, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Tortuga.Chain.DataSources.ISupportsUpsert, Tortuga.Chain.DataSources.ISupportsInsertBulk, Tortuga.Chain.DataSources.ISupportsScalarFunction, Tortuga.Chain.DataSources.ISupportsProcedure, Traits.ICommandHelper, Traits.IInsertBatchHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper, Traits.IUpsertHelper, Traits.IInsertBulkHelper, Traits.ICommandHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsTruncateTrait ___Trait1 = new(); - private Traits.SupportsTruncateTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait2 = new(); - private Traits.SupportsSqlQueriesTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsInsertBatchTrait> ___Trait3 = new(); - private Traits.SupportsInsertBatchTrait> __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait4 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsUpdateTrait ___Trait5 = new(); - private Traits.SupportsUpdateTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsDeleteTrait ___Trait6 = new(); - private Traits.SupportsDeleteTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait7 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsInsertTrait ___Trait8 = new(); - private Traits.SupportsInsertTrait __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsUpdateSet ___Trait9 = new(); - private Traits.SupportsUpdateSet __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsDeleteSet ___Trait10 = new(); - private Traits.SupportsDeleteSet __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - private Traits.SupportsFromTrait ___Trait11 = new(); - private Traits.SupportsFromTrait __Trait11 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait11; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait12 = new(); - private Traits.SupportsGetByKeyListTrait __Trait12 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait12; - } - } - private Traits.SupportsUpsertTrait ___Trait13 = new(); - private Traits.SupportsUpsertTrait __Trait13 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait13; - } - } - private Traits.SupportsInsertBulkTrait ___Trait14 = new(); - private Traits.SupportsInsertBulkTrait __Trait14 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait14; - } - } - private Traits.SupportsScalarFunctionTrait ___Trait15 = new(); - private Traits.SupportsScalarFunctionTrait __Trait15 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait15; - } - } - private Traits.SupportsProcedureTrait ___Trait16 = new(); - private Traits.SupportsProcedureTrait __Trait16 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait16; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait6).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait6).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait4).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBatch - Tortuga.Chain.CommandBuilders.IDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertBatch(objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.String tableName, System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(tableName, objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(objects, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBulk - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, objects); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(objects); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsProcedure - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName); - } - - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsScalarFunction - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName); - } - - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait2).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTruncate - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate() - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait7).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, newValues, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(argumentValue, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.MySql.MySqlObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.MySql.MySqlObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.MySql.MySqlObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait10.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait10.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.MySql.MySqlObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait10.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait10.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait6.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait6.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.MySql.MySqlObjectName tableOrViewName) - { - return __Trait11.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.MySql.MySqlObjectName tableOrViewName, System.String whereClause) - { - return __Trait11.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.MySql.MySqlObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait11.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.MySql.MySqlObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait11.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait11.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait11.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait11.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait11.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.MySql.MySqlObjectName tableName, System.String key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.MySql.MySqlObjectName tableName, TKey key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertBatchTrait> - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// Name of the table. - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.DbCommandBuilder InsertBatch(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.DbCommandBuilder InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(objects, options); - } - - /// - /// Performs a series of batch inserts. - /// - /// The type of the t object. - /// Name of the table. - /// The objects. - /// The options. - /// Tortuga.Chain.ILink<System.Int32>. - /// This operation is not atomic. It should be wrapped in a transaction. - public Tortuga.Chain.ILink InsertMultipleBatch(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.ILink InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(objects, options); - } - - // Exposing trait Traits.SupportsInsertBulkTrait - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data table. - /// TInsertBulkCommand. - public Tortuga.Chain.MySql.CommandBuilders.MySqlInsertBulk InsertBulk(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Data.DataTable dataTable) - { - return __Trait14.InsertBulk(tableName, dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data reader. - /// TInsertBulkCommand. - public Tortuga.Chain.MySql.CommandBuilders.MySqlInsertBulk InsertBulk(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Data.IDataReader dataReader) - { - return __Trait14.InsertBulk(tableName, dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// - /// Name of the table. - /// The objects. - /// TInsertBulkCommand. - public Tortuga.Chain.MySql.CommandBuilders.MySqlInsertBulk InsertBulk(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(tableName, objects); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data table. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.MySql.CommandBuilders.MySqlInsertBulk InsertBulk(System.Data.DataTable dataTable)where TObject : class - { - return __Trait14.InsertBulk(dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data reader. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.MySql.CommandBuilders.MySqlInsertBulk InsertBulk(System.Data.IDataReader dataReader)where TObject : class - { - return __Trait14.InsertBulk(dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The objects. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.MySql.CommandBuilders.MySqlInsertBulk InsertBulk(System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(objects); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsProcedureTrait - - /// - /// Loads a procedure definition - /// - /// Name of the procedure. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.MySql.MySqlObjectName procedureName) - { - return __Trait16.Procedure(procedureName); - } - - /// - /// Loads a procedure definition and populates it using the parameter object. - /// - /// Name of the procedure. - /// The argument value. - /// - /// - /// The procedure's definition is loaded from the database and used to determine which properties on the parameter object to use. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.MySql.MySqlObjectName procedureName, System.Object argumentValue) - { - return __Trait16.Procedure(procedureName, argumentValue); - } - - // Exposing trait Traits.SupportsScalarFunctionTrait - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.MySql.MySqlObjectName scalarFunctionName) - { - return __Trait15.ScalarFunction(scalarFunctionName); - } - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.MySql.MySqlObjectName scalarFunctionName, System.Object functionArgumentValue) - { - return __Trait15.ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait2.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait2.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsTruncateTrait - - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate(Tortuga.Chain.MySql.MySqlObjectName tableName) - { - return __Trait1.Truncate(tableName); - } - - /// Truncates the specified table. - /// This class used to determine which table to Truncate - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate()where TObject : class - { - return __Trait1.Truncate(); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.MySql.MySqlObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.MySql.MySqlObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.MySql.MySqlObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsUpsertTrait - - /// - /// Creates a operation used to perform an "upsert" operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(Tortuga.Chain.MySql.MySqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(tableName, argumentValue, options); - } - - /// - /// Perform an insert or update operation as appropriate. - /// - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.MySql.MySqlObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder OnProcedure(Tortuga.Chain.MySql.MySqlObjectName procedureName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder OnScalarFunction(Tortuga.Chain.MySql.MySqlObjectName scalarFunctionName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private partial Tortuga.Chain.ILink OnTruncate(Tortuga.Chain.MySql.MySqlObjectName tableName ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.OnTruncate = OnTruncate; - __Trait1.DataSource = this; - __Trait2.OnSql = OnSql; - __Trait3.DataSource = this; - __Trait4.DataSource = this; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - __Trait11.DataSource = this; - __Trait12.DataSource = this; - __Trait13.DataSource = this; - __Trait14.DataSource = this; - __Trait15.OnScalarFunction = OnScalarFunction; - __Trait15.DataSource = this; - __Trait16.OnProcedure = OnProcedure; - __Trait16.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlOpenDataSource.cs deleted file mode 100644 index a662d464a..000000000 --- a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.MySql -{ - partial class MySqlOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public MySqlConnector.MySqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public MySqlConnector.MySqlTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.MySql.MySqlMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.MySqlDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private MySqlConnector.MySqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private MySqlConnector.MySqlTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.MySql.MySqlOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.MySql.MySqlOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.MySql.MySqlOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.MySql.MySqlOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlTransactionalDataSource.cs deleted file mode 100644 index 1ab6fc0a9..000000000 --- a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySql.MySqlTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.MySql -{ - partial class MySqlTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public MySqlConnector.MySqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public MySqlConnector.MySqlTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.MySql.MySqlMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.MySqlDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private MySqlConnector.MySqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private MySqlConnector.MySqlTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySqlDataSource.cs b/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySqlDataSource.cs deleted file mode 100644 index c014fb92b..000000000 --- a/Tortuga.Chain/Tortuga.Chain.MySql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.MySqlDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class MySqlDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.MySql.MySqlTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.MySql.MySqlTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public MySqlConnector.MySqlConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.MySql.MySqlOpenDataSource CreateOpenDataSource(MySqlConnector.MySqlConnection connection, MySqlConnector.MySqlTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.MySql.MySqlOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private MySqlConnector.MySqlConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.MySqlDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.MySqlDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.MySqlDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.MySqlDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.MySql.MySqlTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.MySqlDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial MySqlConnector.MySqlConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.MySql.MySqlOpenDataSource OnCreateOpenDataSource(MySqlConnector.MySqlConnection connection, MySqlConnector.MySqlTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteObject`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteObject`1.cs index d1bf42be5..19e856fbb 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteObject`1.cs @@ -3,53 +3,52 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Command object that represents a delete operation. +/// +internal sealed class MySqlDeleteObject : MySqlObjectCommand + where TArgument : class { + readonly DeleteOptions m_Options; + /// - /// Command object that represents a delete operation. + /// Initializes a new instance of the class. /// - internal sealed class MySqlDeleteObject : MySqlObjectCommand - where TArgument : class + /// The data source. + /// The table. + /// The argument value. + /// The options. + public MySqlDeleteObject(MySqlDataSourceBase dataSource, MySqlObjectName table, TArgument argumentValue, DeleteOptions options) + : base(dataSource, table, argumentValue) { - readonly DeleteOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The table. - /// The argument value. - /// The options. - public MySqlDeleteObject(MySqlDataSourceBase dataSource, MySqlObjectName table, TArgument argumentValue, DeleteOptions options) - : base(dataSource, table, argumentValue) - { - m_Options = options; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); - - var sql = new StringBuilder(); - sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); - sql.AppendLine(); - sqlBuilder.BuildDeleteStatement(sql, Table.Name.ToQuotedString(), ";"); - - return new MySqlCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); - } + m_Options = options; + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); + + var sql = new StringBuilder(); + sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); + sql.AppendLine(); + sqlBuilder.BuildDeleteStatement(sql, Table.Name.ToQuotedString(), ";"); + + return new MySqlCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteSet.cs index 1047cfa7f..6187b4435 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlDeleteSet.cs @@ -5,135 +5,134 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class MySqlDeleteSet. +/// +internal sealed class MySqlDeleteSet : MultipleRowDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly int? m_ExpectedRowCount; + readonly FilterOptions m_FilterOptions; + readonly object? m_FilterValue; + readonly DeleteOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly TableOrViewMetadata m_Table; + readonly string? m_WhereClause; + /// - /// Class MySqlDeleteSet. + /// Initializes a new instance of the class. /// - internal sealed class MySqlDeleteSet : MultipleRowDbCommandBuilder + /// The data source. + /// Name of the table. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public MySqlDeleteSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly FilterOptions m_FilterOptions; - readonly object? m_FilterValue; - readonly IEnumerable? m_Parameters; - readonly TableOrViewMetadata m_Table; - readonly string? m_WhereClause; - readonly DeleteOptions m_Options; - readonly int? m_ExpectedRowCount; + if (options.HasFlag(DeleteOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public MySqlDeleteSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) - { - if (options.HasFlag(DeleteOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_Parameters = parameters; - m_Options = options; - m_ExpectedRowCount = expectedRowCount; - } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The argument value. - public MySqlDeleteSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, string whereClause, object? argumentValue) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - } + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_Parameters = parameters; + m_Options = options; + m_ExpectedRowCount = expectedRowCount; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The filter value. - /// The options. - public MySqlDeleteSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The where clause. + /// The argument value. + public MySqlDeleteSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, string whereClause, object? argumentValue) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + } - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The filter value. + /// The options. + public MySqlDeleteSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + } - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - List parameters; - var sql = new StringBuilder(); + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (sqlBuilder.HasReadFields) - { - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, " FROM " + m_Table.Name.ToQuotedString()); - if (m_FilterValue != null) - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - sql.Append(" WHERE " + m_WhereClause); - sql.AppendLine(";"); - } + List parameters; + var sql = new StringBuilder(); - sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); + if (sqlBuilder.HasReadFields) + { + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, " FROM " + m_Table.Name.ToQuotedString()); if (m_FilterValue != null) - { sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - parameters = sqlBuilder.GetParameters(); - } else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { sql.Append(" WHERE " + m_WhereClause); - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } - sql.Append(";"); - - if (m_Parameters != null) - parameters.AddRange(m_Parameters); + sql.AppendLine(";"); + } - return new MySqlCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); + sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); + if (m_FilterValue != null) + { + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + parameters = sqlBuilder.GetParameters(); + } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); } + else + { + parameters = sqlBuilder.GetParameters(); + } + sql.Append(";"); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); + if (m_Parameters != null) + parameters.AddRange(m_Parameters); - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + return new MySqlCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); } -} + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBatch`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBatch`1.cs index 19a83e938..51375f70d 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBatch`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBatch`1.cs @@ -6,94 +6,93 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders -{ - /// - /// Class MySqlInsertBatchTable is when using a values clause with an array of rows. - /// - internal class MySqlInsertBatch : DbCommandBuilder - where TObject : class - { - readonly InsertOptions m_Options; - readonly IReadOnlyList m_SourceList; - readonly TableOrViewMetadata m_Table; - - public MySqlInsertBatch(MySqlDataSourceBase dataSource, MySqlObjectName tableName, IEnumerable objects, InsertOptions options) : base(dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); +namespace Tortuga.Chain.MySql.CommandBuilders; - var sourceList = objects.AsReadOnlyList(); +/// +/// Class MySqlInsertBatchTable is when using a values clause with an array of rows. +/// +internal class MySqlInsertBatch : DbCommandBuilder + where TObject : class +{ + readonly InsertOptions m_Options; + readonly IReadOnlyList m_SourceList; + readonly TableOrViewMetadata m_Table; - if (sourceList == null || sourceList.Count == 0) - throw new ArgumentException($"{nameof(objects)} is null or empty.", nameof(objects)); + public MySqlInsertBatch(MySqlDataSourceBase dataSource, MySqlObjectName tableName, IEnumerable objects, InsertOptions options) : base(dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - m_SourceList = sourceList; - m_Options = options; - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - } + var sourceList = objects.AsReadOnlyList(); - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + if (sourceList == null || sourceList.Count == 0) + throw new ArgumentException($"{nameof(objects)} is null or empty.", nameof(objects)); - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + m_SourceList = sourceList; + m_Options = options; + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + } - //This sets up the sqlBuilder. We're not actually going to build the parameters now - sqlBuilder.ApplyArgumentValue(DataSource, m_SourceList[0], m_Options); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sql = new StringBuilder(); + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + //This sets up the sqlBuilder. We're not actually going to build the parameters now + sqlBuilder.ApplyArgumentValue(DataSource, m_SourceList[0], m_Options); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {m_Table.Name.ToQuotedString()} (", null, ")", identityInsert); - sql.AppendLine("VALUES"); + var sql = new StringBuilder(); - var parameters = new List(); - for (var i = 0; i < m_SourceList.Count; i++) - { - var parameterSuffix = "_" + i; - var footer = (i == m_SourceList.Count - 1) ? ");" : "),"; + bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - sqlBuilder.OverrideArgumentValue(DataSource, AuditRules.OperationTypes.Insert, m_SourceList[i]); - sqlBuilder.BuildValuesClause(sql, "(", footer, identityInsert, parameterSuffix, parameters, Utilities.ParameterBuilderCallback); - } + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {m_Table.Name.ToQuotedString()} (", null, ")", identityInsert); + sql.AppendLine("VALUES"); - var maxParams = DataSource.DatabaseMetadata.MaxParameters!.Value; - if (parameters.Count > maxParams) - { - var parametersPerRow = parameters.Count / m_SourceList.Count; - var maxRows = maxParams / parametersPerRow; - throw new InvalidOperationException($"Batch insert exceeds MySql's parameter limit of {DataSource.DatabaseMetadata.MaxParameters}. Break the call into batches of {maxRows} or use InsertMultipleBatch"); - } + var parameters = new List(); + for (var i = 0; i < m_SourceList.Count; i++) + { + var parameterSuffix = "_" + i; + var footer = (i == m_SourceList.Count - 1) ? ");" : "),"; - return new MySqlCommandExecutionToken(DataSource, "Insert batch into " + m_Table.Name, sql.ToString(), parameters); + sqlBuilder.OverrideArgumentValue(DataSource, AuditRules.OperationTypes.Insert, m_SourceList[i]); + sqlBuilder.BuildValuesClause(sql, "(", footer, identityInsert, parameterSuffix, parameters, Utilities.ParameterBuilderCallback); } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + var maxParams = DataSource.DatabaseMetadata.MaxParameters!.Value; + if (parameters.Count > maxParams) { - return m_Table.Columns.TryGetColumn(columnName); + var parametersPerRow = parameters.Count / m_SourceList.Count; + var maxRows = maxParams / parametersPerRow; + throw new InvalidOperationException($"Batch insert exceeds MySql's parameter limit of {DataSource.DatabaseMetadata.MaxParameters}. Break the call into batches of {maxRows} or use InsertMultipleBatch"); } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + return new MySqlCommandExecutionToken(DataSource, "Insert batch into " + m_Table.Name, sql.ToString(), parameters); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); } -} + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBulk.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBulk.cs index 3dbfe5878..87ec23e57 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBulk.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertBulk.cs @@ -6,300 +6,299 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// This class is used to perform bulk inserts +/// +public sealed class MySqlInsertBulk : DbOperationBuilder { + readonly MySqlDataSourceBase m_DataSource; + readonly IDataReader m_Source; + readonly TableOrViewMetadata m_Table; + int? m_BatchSize; + EventHandler? m_EventHandler; + int? m_NotifyAfter; + + internal MySqlInsertBulk(MySqlDataSourceBase dataSource, MySqlObjectName tableName, DataTable dataTable) : base(dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (dataTable == null) + throw new ArgumentNullException(nameof(dataTable), $"{nameof(dataTable)} is null."); + + m_DataSource = dataSource; + m_Source = dataTable.CreateDataReader(); + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + if (!m_Table.IsTable) + throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); + } + + internal MySqlInsertBulk(MySqlDataSourceBase dataSource, MySqlObjectName tableName, IDataReader dataReader) : base(dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (dataReader == null) + throw new ArgumentNullException(nameof(dataReader), $"{nameof(dataReader)} is null."); + + m_DataSource = dataSource; + m_Source = dataReader; + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + if (!m_Table.IsTable) + throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); + } + /// - /// This class is used to perform bulk inserts + /// Prepares the command for execution by generating any necessary SQL. /// - public sealed class MySqlInsertBulk : DbOperationBuilder + /// ExecutionToken<TCommand>. + public override OperationExecutionToken Prepare() { - readonly MySqlDataSourceBase m_DataSource; - readonly IDataReader m_Source; - readonly TableOrViewMetadata m_Table; - int? m_BatchSize; - EventHandler? m_EventHandler; - int? m_NotifyAfter; - - internal MySqlInsertBulk(MySqlDataSourceBase dataSource, MySqlObjectName tableName, DataTable dataTable) : base(dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (dataTable == null) - throw new ArgumentNullException(nameof(dataTable), $"{nameof(dataTable)} is null."); - - m_DataSource = dataSource; - m_Source = dataTable.CreateDataReader(); - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - if (!m_Table.IsTable) - throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); - } + return new OperationExecutionToken(m_DataSource, "Bulk Insert into " + m_Table.Name); + } - internal MySqlInsertBulk(MySqlDataSourceBase dataSource, MySqlObjectName tableName, IDataReader dataReader) : base(dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (dataReader == null) - throw new ArgumentNullException(nameof(dataReader), $"{nameof(dataReader)} is null."); - - m_DataSource = dataSource; - m_Source = dataReader; - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - if (!m_Table.IsTable) - throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - /// - /// Modifies the batch size. - /// - /// Size of the batch. - /// SqlServerInsertBulk. - public MySqlInsertBulk WithBatchSize(int batchSize) - { - m_BatchSize = batchSize; - return this; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// ExecutionToken<TCommand>. - public override OperationExecutionToken Prepare() - { - return new OperationExecutionToken(m_DataSource, "Bulk Insert into " + m_Table.Name); - } + /// + /// Modifies the batch size. + /// + /// Size of the batch. + /// SqlServerInsertBulk. + public MySqlInsertBulk WithBatchSize(int batchSize) + { + m_BatchSize = batchSize; + return this; + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// After notifyAfter records, the event handler may be fired. This can be used to abort the bulk insert. - /// - /// The event handler. - /// The notify after. This should be a multiple of the batch size. - public MySqlInsertBulk WithNotifications(EventHandler eventHandler, int notifyAfter) - { - if (eventHandler == null) - throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); - if (notifyAfter <= 0) - throw new ArgumentException($"{nameof(notifyAfter)} must be greater than 0.", nameof(notifyAfter)); - m_EventHandler = eventHandler; - m_NotifyAfter = notifyAfter; - return this; - } + /// + /// After notifyAfter records, the event handler may be fired. This can be used to abort the bulk insert. + /// + /// The event handler. + /// The notify after. This should be a multiple of the batch size. + public MySqlInsertBulk WithNotifications(EventHandler eventHandler, int notifyAfter) + { + if (eventHandler == null) + throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); + if (notifyAfter <= 0) + throw new ArgumentException($"{nameof(notifyAfter)} must be greater than 0.", nameof(notifyAfter)); + m_EventHandler = eventHandler; + m_NotifyAfter = notifyAfter; + return this; + } - /// - /// Implementation the specified operation. - /// - /// The connection. - /// The transaction. - /// System.Nullable<System.Int32>. - protected override int? Implementation(MySqlConnection connection, MySqlTransaction? transaction) + /// + /// Implementation the specified operation. + /// + /// The connection. + /// The transaction. + /// System.Nullable<System.Int32>. + protected override int? Implementation(MySqlConnection connection, MySqlTransaction? transaction) + { + var bl = new MySqlBulkLoader(connection); + var mappedColumns = SetupBulkCopy(bl); + + var lastNotification = 0; + var totalCount = 0; + var rowCount = 0; + var output = new StringBuilder(); + while (m_Source.Read()) { - var bl = new MySqlBulkLoader(connection); - var mappedColumns = SetupBulkCopy(bl); - - var lastNotification = 0; - var totalCount = 0; - var rowCount = 0; - var output = new StringBuilder(); - while (m_Source.Read()) - { - rowCount += 1; - WriteRow(mappedColumns, output); - if (rowCount == m_BatchSize) - { - using (var ms = CreateMemoryStream(output)) - { - bl.FileName = null; - bl.SourceStream = ms; - totalCount += bl.Load(); - - output.Clear(); - } - - //We only notify after a batch has been posted to the server. - if (m_NotifyAfter.HasValue && m_EventHandler != null) - { - var notificationCount = totalCount % m_NotifyAfter.Value; - - if ((totalCount % m_NotifyAfter) > notificationCount) - { - lastNotification = notificationCount; - var e = new AbortableOperationEventArgs(totalCount); - m_EventHandler?.Invoke(this, e); - if (e.Abort) - throw new TaskCanceledException("Bulk insert operation aborted."); - } - } - - rowCount = 0; - } - } - - if (rowCount > 0) //final batch + rowCount += 1; + WriteRow(mappedColumns, output); + if (rowCount == m_BatchSize) { using (var ms = CreateMemoryStream(output)) { bl.FileName = null; bl.SourceStream = ms; totalCount += bl.Load(); + + output.Clear(); } - if (m_EventHandler != null) + //We only notify after a batch has been posted to the server. + if (m_NotifyAfter.HasValue && m_EventHandler != null) { - var e = new AbortableOperationEventArgs(totalCount); - m_EventHandler?.Invoke(this, e); - //can't abort at this point; + var notificationCount = totalCount % m_NotifyAfter.Value; + + if ((totalCount % m_NotifyAfter) > notificationCount) + { + lastNotification = notificationCount; + var e = new AbortableOperationEventArgs(totalCount); + m_EventHandler?.Invoke(this, e); + if (e.Abort) + throw new TaskCanceledException("Bulk insert operation aborted."); + } } - } - return totalCount; + rowCount = 0; + } } - /// - /// Implementation the specified operation. - /// - /// The connection. - /// The transaction. - /// The cancellation token. - /// Task<System.Nullable<System.Int32>>. - protected override async Task ImplementationAsync(MySqlConnection connection, MySqlTransaction? transaction, CancellationToken cancellationToken) + if (rowCount > 0) //final batch { - var bl = new MySqlBulkLoader(connection); - var mappedColumns = SetupBulkCopy(bl); - - var totalCount = 0; - var rowCount = 0; - var output = new StringBuilder(); - while (m_Source.Read()) + using (var ms = CreateMemoryStream(output)) { - rowCount += 1; - WriteRow(mappedColumns, output); - if (rowCount == m_BatchSize) - { - using (var ms = CreateMemoryStream(output)) - { - bl.FileName = null; - bl.SourceStream = ms; - totalCount += await bl.LoadAsync(cancellationToken).ConfigureAwait(false); + bl.FileName = null; + bl.SourceStream = ms; + totalCount += bl.Load(); + } - output.Clear(); - } - rowCount = 0; - } + if (m_EventHandler != null) + { + var e = new AbortableOperationEventArgs(totalCount); + m_EventHandler?.Invoke(this, e); + //can't abort at this point; } + } + + return totalCount; + } + + /// + /// Implementation the specified operation. + /// + /// The connection. + /// The transaction. + /// The cancellation token. + /// Task<System.Nullable<System.Int32>>. + protected override async Task ImplementationAsync(MySqlConnection connection, MySqlTransaction? transaction, CancellationToken cancellationToken) + { + var bl = new MySqlBulkLoader(connection); + var mappedColumns = SetupBulkCopy(bl); - if (rowCount > 0) //final batch + var totalCount = 0; + var rowCount = 0; + var output = new StringBuilder(); + while (m_Source.Read()) + { + rowCount += 1; + WriteRow(mappedColumns, output); + if (rowCount == m_BatchSize) { using (var ms = CreateMemoryStream(output)) { bl.FileName = null; bl.SourceStream = ms; totalCount += await bl.LoadAsync(cancellationToken).ConfigureAwait(false); + + output.Clear(); } + rowCount = 0; } - - return totalCount; } - MemoryStream CreateMemoryStream(StringBuilder output) + if (rowCount > 0) //final batch { - var memoryStreamBytes = Encoding.UTF8.GetBytes(output.ToString()); - return new MemoryStream(memoryStreamBytes, false); + using (var ms = CreateMemoryStream(output)) + { + bl.FileName = null; + bl.SourceStream = ms; + totalCount += await bl.LoadAsync(cancellationToken).ConfigureAwait(false); + } } - void WriteRow(List mappedColumns, StringBuilder output) + return totalCount; + } + + MemoryStream CreateMemoryStream(StringBuilder output) + { + var memoryStreamBytes = Encoding.UTF8.GetBytes(output.ToString()); + return new MemoryStream(memoryStreamBytes, false); + } + + List SetupBulkCopy(MySqlBulkLoader bl) + { + bl.TableName = m_Table.Name.ToString(); + bl.CharacterSet = "UTF8"; + bl.NumberOfLinesToSkip = 0; + bl.FieldTerminator = ","; + bl.FieldQuotationCharacter = '"'; + bl.FieldQuotationOptional = false; + bl.LineTerminator = Environment.NewLine; + bl.Local = true; + + var mappedColumns = new List(m_Source.FieldCount); + for (var i = 0; i < m_Source.FieldCount; i++) { - foreach (var i in mappedColumns) - { - var value = m_Source.GetValue(i); - switch (value) - { - case Guid g: - output.Append("\"" + g.ToString() + "\""); - break; - - case string s: - output.Append("\"" + - s - .Replace("\"", "\\\"") - .Replace("\t", @"\t") - .Replace("\r", @"\r") - .Replace("\n", @"\n") - + "\""); - break; - - case bool b: - output.Append(b ? "1" : "0"); - break; - - case DateTime dt: - output.Append(dt.ToString("yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture)); - break; - - case DateTimeOffset dto: - output.Append(dto.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture)); - break; - - case null: - output.Append("NULL"); - break; - - default: - value.ToString(); //this would cover numbers - break; - } + bl.Columns.Add(m_Source.GetName(i)); - if (i == mappedColumns.Count - 1) - output.Append(Environment.NewLine); - else - output.Append(","); - } + if (m_Table.Columns.TryGetColumn(m_Source.GetName(i)) != null) + mappedColumns.Add(i); + else if (StrictMode) + throw new MappingException($"Could not find column on {m_Table.Name.ToString()} that matches property {m_Source.GetName(i)}"); } + if (mappedColumns.Count == 0) + throw new MappingException($"Could not find any properties that map to columns on the table {m_Table.Name.ToString()}"); + + return mappedColumns; + } - List SetupBulkCopy(MySqlBulkLoader bl) + void WriteRow(List mappedColumns, StringBuilder output) + { + foreach (var i in mappedColumns) { - bl.TableName = m_Table.Name.ToString(); - bl.CharacterSet = "UTF8"; - bl.NumberOfLinesToSkip = 0; - bl.FieldTerminator = ","; - bl.FieldQuotationCharacter = '"'; - bl.FieldQuotationOptional = false; - bl.LineTerminator = Environment.NewLine; - bl.Local = true; - - var mappedColumns = new List(m_Source.FieldCount); - for (var i = 0; i < m_Source.FieldCount; i++) + var value = m_Source.GetValue(i); + switch (value) { - bl.Columns.Add(m_Source.GetName(i)); - - if (m_Table.Columns.TryGetColumn(m_Source.GetName(i)) != null) - mappedColumns.Add(i); - else if (StrictMode) - throw new MappingException($"Could not find column on {m_Table.Name.ToString()} that matches property {m_Source.GetName(i)}"); + case Guid g: + output.Append("\"" + g.ToString() + "\""); + break; + + case string s: + output.Append("\"" + + s + .Replace("\"", "\\\"") + .Replace("\t", @"\t") + .Replace("\r", @"\r") + .Replace("\n", @"\n") + + "\""); + break; + + case bool b: + output.Append(b ? "1" : "0"); + break; + + case DateTime dt: + output.Append(dt.ToString("yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture)); + break; + + case DateTimeOffset dto: + output.Append(dto.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss.ffffff", CultureInfo.InvariantCulture)); + break; + + case null: + output.Append("NULL"); + break; + + default: + value.ToString(); //this would cover numbers + break; } - if (mappedColumns.Count == 0) - throw new MappingException($"Could not find any properties that map to columns on the table {m_Table.Name.ToString()}"); - return mappedColumns; + if (i == mappedColumns.Count - 1) + output.Append(Environment.NewLine); + else + output.Append(","); } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertObject`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertObject`1.cs index 88010e756..831fefcc2 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertObject`1.cs @@ -3,76 +3,75 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class that represents a MySql Insert. +/// +internal sealed class MySqlInsertObject : MySqlObjectCommand + where TArgument : class { + readonly InsertOptions m_Options; + /// - /// Class that represents a MySql Insert. + /// Initializes a new instance of the class. /// - internal sealed class MySqlInsertObject : MySqlObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public MySqlInsertObject(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue, InsertOptions options) + : base(dataSource, tableName, argumentValue) { - readonly InsertOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public MySqlInsertObject(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue, InsertOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + var identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var sql = new StringBuilder(); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToString()} (", null, ")", identityInsert); - sqlBuilder.BuildValuesClause(sql, " VALUES (", ");", identityInsert); + var sql = new StringBuilder(); + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToString()} (", null, ")", identityInsert); + sqlBuilder.BuildValuesClause(sql, " VALUES (", ");", identityInsert); - if (sqlBuilder.HasReadFields) + if (sqlBuilder.HasReadFields) + { + var identityColumn = Table.Columns.Where(c => c.IsIdentity).SingleOrDefault(); + if (!identityInsert && identityColumn != null) { - var identityColumn = Table.Columns.Where(c => c.IsIdentity).SingleOrDefault(); - if (!identityInsert && identityColumn != null) - { - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - sql.Append(" FROM " + Table.Name.ToQuotedString()); - sql.Append(" WHERE " + identityColumn.QuotedSqlName + " = LAST_INSERT_ID()"); - sql.Append(";"); - } - else - { - var primaryKeys = Table.PrimaryKeyColumns; - if (primaryKeys.Count == 0) - throw new MappingException($"Insert operation cannot return any values for { Table.Name} because it doesn't have a primary key."); - - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - sql.Append(" FROM " + Table.Name.ToQuotedString()); - sqlBuilder.BuildWhereClause(sql, " WHERE ", null); - sql.Append(";"); - } + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + sql.Append(" FROM " + Table.Name.ToQuotedString()); + sql.Append(" WHERE " + identityColumn.QuotedSqlName + " = LAST_INSERT_ID()"); + sql.Append(";"); } + else + { + var primaryKeys = Table.PrimaryKeyColumns; + if (primaryKeys.Count == 0) + throw new MappingException($"Insert operation cannot return any values for { Table.Name} because it doesn't have a primary key."); - return new MySqlCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + sql.Append(" FROM " + Table.Name.ToQuotedString()); + sqlBuilder.BuildWhereClause(sql, " WHERE ", null); + sql.Append(";"); + } } + + return new MySqlCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertOrUpdateObject`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertOrUpdateObject`1.cs index 465dc1876..b7a3757b2 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertOrUpdateObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlInsertOrUpdateObject`1.cs @@ -3,82 +3,81 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class MySqlInsertOrUpdateObject +/// +internal sealed class MySqlInsertOrUpdateObject : MySqlObjectCommand + where TArgument : class { + private readonly UpsertOptions m_Options; + /// - /// Class MySqlInsertOrUpdateObject + /// Initializes a new instance of the class. /// - internal sealed class MySqlInsertOrUpdateObject : MySqlObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public MySqlInsertOrUpdateObject(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue, UpsertOptions options) + : base(dataSource, tableName, argumentValue) { - private readonly UpsertOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public MySqlInsertOrUpdateObject(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue, UpsertOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var identityInsert = m_Options.HasFlag(UpsertOptions.IdentityInsert); + var identityInsert = m_Options.HasFlag(UpsertOptions.IdentityInsert); - var sql = new StringBuilder(); - List keyParameters; - var isPrimaryKeyIdentity = sqlBuilder.PrimaryKeyIsIdentity(out keyParameters); - if (isPrimaryKeyIdentity && !identityInsert) - { - var areKeysNull = keyParameters.Any(c => c.Value == DBNull.Value || c.Value == null) ? true : false; - if (areKeysNull) - sqlBuilder.BuildInsertStatement(sql, Table.Name.ToString(), null); - else - sqlBuilder.BuildUpdateByKeyStatement(sql, Table.Name.ToString(), null); - sql.Append(";"); - } + var sql = new StringBuilder(); + List keyParameters; + var isPrimaryKeyIdentity = sqlBuilder.PrimaryKeyIsIdentity(out keyParameters); + if (isPrimaryKeyIdentity && !identityInsert) + { + var areKeysNull = keyParameters.Any(c => c.Value == DBNull.Value || c.Value == null) ? true : false; + if (areKeysNull) + sqlBuilder.BuildInsertStatement(sql, Table.Name.ToString(), null); else - { - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToString()} (", null, ")", identityInsert); - sqlBuilder.BuildValuesClause(sql, " VALUES (", ")", identityInsert); - sqlBuilder.BuildSetClause(sql, $" ON DUPLICATE KEY UPDATE ", null, null); - sql.Append(";"); - } - - if (sqlBuilder.HasReadFields) - { - var keys = sqlBuilder.GetKeyColumns().ToList(); - if (keys.Count != 1) - throw new NotSupportedException("Cannot return data from a MySQL Upsert unless there is a single primary key."); - var key = keys[0]; + sqlBuilder.BuildUpdateByKeyStatement(sql, Table.Name.ToString(), null); + sql.Append(";"); + } + else + { + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToString()} (", null, ")", identityInsert); + sqlBuilder.BuildValuesClause(sql, " VALUES (", ")", identityInsert); + sqlBuilder.BuildSetClause(sql, $" ON DUPLICATE KEY UPDATE ", null, null); + sql.Append(";"); + } - if (KeyColumns.Count == 0) - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, $" FROM {Table.Name.ToQuotedString()} WHERE {key.QuotedSqlName} = CASE WHEN {key.SqlVariableName} IS NULL OR {key.SqlVariableName} = 0 THEN LAST_INSERT_ID() ELSE {key.SqlVariableName} END;"); - else - sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); - } + if (sqlBuilder.HasReadFields) + { + var keys = sqlBuilder.GetKeyColumns().ToList(); + if (keys.Count != 1) + throw new NotSupportedException("Cannot return data from a MySQL Upsert unless there is a single primary key."); + var key = keys[0]; - return new MySqlCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); + if (KeyColumns.Count == 0) + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, $" FROM {Table.Name.ToQuotedString()} WHERE {key.QuotedSqlName} = CASE WHEN {key.SqlVariableName} IS NULL OR {key.SqlVariableName} = 0 THEN LAST_INSERT_ID() ELSE {key.SqlVariableName} END;"); + else + sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); } + + return new MySqlCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlObjectCommand`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlObjectCommand`1.cs index 6ee49a45d..aee00d106 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlObjectCommand`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlObjectCommand`1.cs @@ -2,35 +2,34 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Base class that describes a MySql database command. +/// +internal abstract class MySqlObjectCommand : ObjectDbCommandBuilder + where TArgument : class { /// - /// Base class that describes a MySql database command. + /// Initializes a new instance of the class. /// - internal abstract class MySqlObjectCommand : ObjectDbCommandBuilder - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + protected MySqlObjectCommand(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue) + : base(dataSource, argumentValue) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - protected MySqlObjectCommand(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue) - : base(dataSource, argumentValue) - { - Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - } + Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + } - /// - /// Gets the table metadata. - /// - public TableOrViewMetadata Table { get; } + /// + /// Gets the table metadata. + /// + public TableOrViewMetadata Table { get; } - /// - /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. - /// - /// - protected override TableOrViewMetadata OnGetTable() => Table; - } -} + /// + /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. + /// + /// + protected override TableOrViewMetadata OnGetTable() => Table; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlProcedureCall.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlProcedureCall.cs index 3b0cef620..343463c8d 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlProcedureCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlProcedureCall.cs @@ -1,93 +1,91 @@ using MySqlConnector; using System.Collections.Immutable; -using Tortuga.Chain.AuditRules; using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class MySqlProcedureCall. +/// +internal sealed class MySqlProcedureCall : ProcedureDbCommandBuilder { + private readonly object? m_ArgumentValue; + private readonly StoredProcedureMetadata m_Procedure; + /// - /// Class MySqlProcedureCall. + /// Initializes a new instance of the class. /// - internal sealed class MySqlProcedureCall : ProcedureDbCommandBuilder + /// The data source. + /// Name of the procedure. + /// The argument value. + internal MySqlProcedureCall(MySqlDataSourceBase dataSource, MySqlObjectName procedureName, object? argumentValue = null) : base(dataSource) { - private readonly object? m_ArgumentValue; - private readonly StoredProcedureMetadata m_Procedure; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the procedure. - /// The argument value. - internal MySqlProcedureCall(MySqlDataSourceBase dataSource, MySqlObjectName procedureName, object? argumentValue = null) : base(dataSource) - { - if (procedureName == MySqlObjectName.Empty) - throw new ArgumentException($"{nameof(procedureName)} is empty", nameof(procedureName)); + if (procedureName == MySqlObjectName.Empty) + throw new ArgumentException($"{nameof(procedureName)} is empty", nameof(procedureName)); - m_ArgumentValue = argumentValue; - m_Procedure = DataSource.DatabaseMetadata.GetStoredProcedure(procedureName); - } - - /// - /// Gets the data source. - /// - /// The data source. - public new MySqlDataSourceBase DataSource - { - get { return (MySqlDataSourceBase)base.DataSource; } - } + m_ArgumentValue = argumentValue; + m_Procedure = DataSource.DatabaseMetadata.GetStoredProcedure(procedureName); + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Gets the data source. + /// + /// The data source. + public new MySqlDataSourceBase DataSource + { + get { return (MySqlDataSourceBase)base.DataSource; } + } - List parameters; + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (m_ArgumentValue is IEnumerable) - { - parameters = ((IEnumerable)m_ArgumentValue).ToList(); - } - else - { - var sqlBuilder = m_Procedure.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, m_ArgumentValue); - parameters = sqlBuilder.GetParameters(); - } + List parameters; - return new MySqlCommandExecutionToken(DataSource, m_Procedure.Name.ToString(), m_Procedure.Name.ToQuotedString(), parameters, CommandType.StoredProcedure); + if (m_ArgumentValue is IEnumerable) + { + parameters = ((IEnumerable)m_ArgumentValue).ToList(); } - - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + else { - return null; + var sqlBuilder = m_Procedure.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, m_ArgumentValue); + parameters = sqlBuilder.GetParameters(); } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; + return new MySqlCommandExecutionToken(DataSource, m_Procedure.Name.ToString(), m_Procedure.Name.ToQuotedString(), parameters, CommandType.StoredProcedure); } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return null; + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlScalarFunction.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlScalarFunction.cs index caa4657b3..268a896ad 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlScalarFunction.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlScalarFunction.cs @@ -7,81 +7,80 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Use for scalar functions. +/// +/// +internal class MySqlScalarFunction : ScalarDbCommandBuilder { + private readonly ScalarFunctionMetadata m_Function; + private readonly object? m_FunctionArgumentValue; + /// - /// Use for scalar functions. + /// Initializes a new instance of the class. /// - /// - internal class MySqlScalarFunction : ScalarDbCommandBuilder + /// The data source. + /// Name of the scalar function. + /// The function argument. + public MySqlScalarFunction(MySqlDataSourceBase dataSource, MySqlObjectName scalarFunctionName, object? functionArgumentValue) : base(dataSource) { - private readonly ScalarFunctionMetadata m_Function; - private readonly object? m_FunctionArgumentValue; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the scalar function. - /// The function argument. - public MySqlScalarFunction(MySqlDataSourceBase dataSource, MySqlObjectName scalarFunctionName, object? functionArgumentValue) : base(dataSource) - { - m_Function = dataSource.DatabaseMetadata.GetScalarFunction(scalarFunctionName); - m_FunctionArgumentValue = functionArgumentValue; - } + m_Function = dataSource.DatabaseMetadata.GetScalarFunction(scalarFunctionName); + m_FunctionArgumentValue = functionArgumentValue; + } - /// - /// Gets the data source. - /// - /// The data source. - public new MySqlDataSourceBase DataSource => (MySqlDataSourceBase)base.DataSource; + /// + /// Gets the data source. + /// + /// The data source. + public new MySqlDataSourceBase DataSource => (MySqlDataSourceBase)base.DataSource; - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sqlBuilder = m_Function.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); + var sqlBuilder = m_Function.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); - if (m_FunctionArgumentValue != null) - sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); + if (m_FunctionArgumentValue != null) + sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); - var sql = new StringBuilder(); - sqlBuilder.BuildFromFunctionClause(sql, $"SELECT {m_Function.Name.ToQuotedString()} (", " )", "?"); - sql.Append(";"); + var sql = new StringBuilder(); + sqlBuilder.BuildFromFunctionClause(sql, $"SELECT {m_Function.Name.ToQuotedString()} (", " )", "?"); + sql.Append(";"); - List parameters; - parameters = sqlBuilder.GetParameters(); + List parameters; + parameters = sqlBuilder.GetParameters(); - return new MySqlCommandExecutionToken(DataSource, "Query Function " + m_Function.Name, sql.ToString(), parameters); - } + return new MySqlCommandExecutionToken(DataSource, "Query Function " + m_Function.Name, sql.ToString(), parameters); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// ColumnMetadata. - /// Always returns null since this command builder has no columns - public override ColumnMetadata? TryGetColumn(string columnName) => null; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// ColumnMetadata. + /// Always returns null since this command builder has no columns + public override ColumnMetadata? TryGetColumn(string columnName) => null; - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlSqlCall.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlSqlCall.cs index ba3c53f0a..6d966a7af 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlSqlCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlSqlCall.cs @@ -5,66 +5,65 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class MySqlSqlCall +/// +public class MySqlSqlCall : MultipleTableDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly string m_SqlStatement; + /// - /// Class MySqlSqlCall + /// Initializes a new instance of the class. /// - public class MySqlSqlCall : MultipleTableDbCommandBuilder + /// The data source. + /// The SQL statement. + /// The argument value. + /// sqlStatement is null or empty.;sqlStatement + public MySqlSqlCall(MySqlDataSourceBase dataSource, string sqlStatement, object? argumentValue) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly string m_SqlStatement; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The SQL statement. - /// The argument value. - /// sqlStatement is null or empty.;sqlStatement - public MySqlSqlCall(MySqlDataSourceBase dataSource, string sqlStatement, object? argumentValue) : base(dataSource) - { - if (string.IsNullOrEmpty(sqlStatement)) - throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); - - m_SqlStatement = sqlStatement; - m_ArgumentValue = argumentValue; - } + if (string.IsNullOrEmpty(sqlStatement)) + throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - return new MySqlCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); - } + m_SqlStatement = sqlStatement; + m_ArgumentValue = argumentValue; + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) - { - return null; - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + return new MySqlCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return null; } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlTableOrView.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlTableOrView.cs index 659bd61fe..57ca83d52 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlTableOrView.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlTableOrView.cs @@ -5,320 +5,330 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class MySqlTableOrView +/// +public class MySqlTableOrView : TableDbCommandBuilder + where TObject : class { + private readonly TableOrViewMetadata m_Table; + private object? m_ArgumentValue; + private FilterOptions m_FilterOptions; + private object? m_FilterValue; + private MySqlLimitOption m_LimitOptions; + private int? m_Seed; + private string? m_SelectClause; + private int? m_Skip; + private IEnumerable m_SortExpressions = Enumerable.Empty(); + private int? m_Take; + private string? m_WhereClause; + /// - /// Class MySqlTableOrView + /// Initializes a new instance of the class. /// - public class MySqlTableOrView : TableDbCommandBuilder - where TObject : class + /// The data source. + /// Name of the table or view. + /// + public MySqlTableOrView(MySqlDataSourceBase dataSource, MySqlObjectName tableOrViewName) : + base(dataSource) { - private readonly TableOrViewMetadata m_Table; - private object? m_ArgumentValue; - private FilterOptions m_FilterOptions; - private object? m_FilterValue; - private MySqlLimitOption m_LimitOptions; - private int? m_Seed; - private string? m_SelectClause; - private int? m_Skip; - private IEnumerable m_SortExpressions = Enumerable.Empty(); - private int? m_Take; - private string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// - public MySqlTableOrView(MySqlDataSourceBase dataSource, MySqlObjectName tableOrViewName) : - base(dataSource) - { - if (tableOrViewName == MySqlObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + if (tableOrViewName == MySqlObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - } + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// tableOrViewName - tableOrViewName - /// - public MySqlTableOrView(MySqlDataSourceBase dataSource, MySqlObjectName tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None) : - base(dataSource) - { - if (tableOrViewName == MySqlObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table or view. + /// The filter value. + /// The filter options. + /// tableOrViewName - tableOrViewName + /// + public MySqlTableOrView(MySqlDataSourceBase dataSource, MySqlObjectName tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None) : + base(dataSource) + { + if (tableOrViewName == MySqlObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - m_FilterValue = filterValue; - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - m_FilterOptions = filterOptions; - } + m_FilterValue = filterValue; + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + m_FilterOptions = filterOptions; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The where clause. - /// The argument value. - /// - public MySqlTableOrView(MySqlDataSourceBase dataSource, MySqlObjectName tableOrViewName, string? whereClause, object? argumentValue) - : base(dataSource) - { - if (tableOrViewName == MySqlObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table or view. + /// The where clause. + /// The argument value. + /// + public MySqlTableOrView(MySqlDataSourceBase dataSource, MySqlObjectName tableOrViewName, string? whereClause, object? argumentValue) + : base(dataSource) + { + if (tableOrViewName == MySqlObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - } + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + } - /// - /// Gets the data source. - /// - /// The data source. - public new MySqlDataSourceBase DataSource - { - get { return (MySqlDataSourceBase)base.DataSource; } - } + /// + /// Gets the data source. + /// + /// The data source. + public new MySqlDataSourceBase DataSource + { + get { return (MySqlDataSourceBase)base.DataSource; } + } - /// - /// Returns the row count using a SELECT COUNT_BIG(*) style query. - /// - /// - public override ILink AsCount() - { - m_SelectClause = "COUNT(*)"; - return ToInt64(); - } + /// + /// Returns the row count using a SELECT COUNT_BIG(*) style query. + /// + /// + public override ILink AsCount() + { + m_SelectClause = "COUNT(*)"; + return ToInt64(); + } - /// - /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). - /// - public override ILink AsCount(string columnName, bool distinct = false) - { - var column = m_Table.Columns[columnName]; - if (distinct) - m_SelectClause = $"COUNT(DISTINCT {column.QuotedSqlName})"; - else - m_SelectClause = $"COUNT({column.QuotedSqlName})"; + /// + /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). + /// + public override ILink AsCount(string columnName, bool distinct = false) + { + var column = m_Table.Columns[columnName]; + if (distinct) + m_SelectClause = $"COUNT(DISTINCT {column.QuotedSqlName})"; + else + m_SelectClause = $"COUNT({column.QuotedSqlName})"; - return ToInt64(); - } + return ToInt64(); + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); + + if (m_SelectClause == null) + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + //Support check + if (!Enum.IsDefined(typeof(MySqlLimitOption), m_LimitOptions)) + throw new NotSupportedException($"MySQL does not support limit option {(LimitOptions)m_LimitOptions}"); + + //Validation + if (m_Skip < 0) + throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); + + if (m_Skip > 0 && m_LimitOptions != MySqlLimitOption.Rows) + throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); + + if (m_Take <= 0) + throw new InvalidOperationException($"Cannot take {m_Take} rows"); + + if (m_LimitOptions == MySqlLimitOption.RandomSampleRows && m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform random sampling when sorting."); - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - public override CommandExecutionToken Prepare(Materializer materializer) + //SQL Generation + List parameters; + var sql = new StringBuilder(); + + if (m_SelectClause != null) + sql.Append($"SELECT {m_SelectClause} "); + else + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); + + sql.Append(" FROM " + m_Table.Name); + + if (m_FilterValue != null) { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); - - if (m_SelectClause == null) - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - //Support check - if (!Enum.IsDefined(typeof(MySqlLimitOption), m_LimitOptions)) - throw new NotSupportedException($"MySQL does not support limit option {(LimitOptions)m_LimitOptions}"); - - //Validation - if (m_Skip < 0) - throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); - - if (m_Skip > 0 && m_LimitOptions != MySqlLimitOption.Rows) - throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); - - if (m_Take <= 0) - throw new InvalidOperationException($"Cannot take {m_Take} rows"); - - if (m_LimitOptions == MySqlLimitOption.RandomSampleRows && m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform random sampling when sorting."); - - //SQL Generation - List parameters; - var sql = new StringBuilder(); - - if (m_SelectClause != null) - sql.Append($"SELECT {m_SelectClause} "); - else - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, null); - - sql.Append(" FROM " + m_Table.Name); - - if (m_FilterValue != null) - { - sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE (" + m_WhereClause + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); - parameters = sqlBuilder.GetParameters(); - } - - switch (m_LimitOptions) - { - case MySqlLimitOption.RandomSampleRows: - if (m_Seed.HasValue) - sql.Append($" ORDER BY RAND({m_Seed}) "); - else - sql.Append(" ORDER BY RAND() "); - break; - - default: - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); - break; - } - - switch (m_LimitOptions) - { - case MySqlLimitOption.Rows: - - if (m_Skip.HasValue) - { - sql.Append(" LIMIT @offset_row_count_expression, @limit_row_count_expression"); - parameters.Add(new MySqlParameter("@offset_row_count_expression", m_Skip)); - parameters.Add(new MySqlParameter("@limit_row_count_expression", m_Take)); - } - else - { - sql.Append(" LIMIT @limit_row_count_expression"); - parameters.Add(new MySqlParameter("@limit_row_count_expression", m_Take)); - } - - break; - } - - sql.Append(";"); - - return new MySqlCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); + sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); + + parameters = sqlBuilder.GetParameters(); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE (" + m_WhereClause + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - return m_Table.Columns.TryGetColumn(columnName); + sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); + parameters = sqlBuilder.GetParameters(); } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + switch (m_LimitOptions) { - m_FilterValue = filterValue; - m_WhereClause = null; - m_ArgumentValue = null; - m_FilterOptions = filterOptions; - return this; + case MySqlLimitOption.RandomSampleRows: + if (m_Seed.HasValue) + sql.Append($" ORDER BY RAND({m_Seed}) "); + else + sql.Append(" ORDER BY RAND() "); + break; + + default: + + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any()) + { + if (m_Table.HasPrimaryKey) + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_Table.PrimaryKeyColumns.Select(x => new SortExpression(x.SqlName)), null); + else if (StrictMode) + throw new InvalidOperationException("Limits were requested, but no primary keys were detected. Use WithSorting to supply a sort order or disable strict mode."); + } + else + { + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + } + break; } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + switch (m_LimitOptions) { - m_FilterValue = null; - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - return this; + case MySqlLimitOption.Rows: + + if (m_Skip.HasValue) + { + sql.Append(" LIMIT @offset_row_count_expression, @limit_row_count_expression"); + parameters.Add(new MySqlParameter("@offset_row_count_expression", m_Skip)); + parameters.Add(new MySqlParameter("@limit_row_count_expression", m_Take)); + } + else + { + sql.Append(" LIMIT @limit_row_count_expression"); + parameters.Add(new MySqlParameter("@limit_row_count_expression", m_Take)); + } + + break; } - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + sql.Append(";"); - m_SortExpressions = sortExpressions; - return this; - } + return new MySqlCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); + } - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, MySqlLimitOption limitOptions, int? seed) - { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = limitOptions; - return this; - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) - { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = (MySqlLimitOption)limitOptions; - return this; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_FilterValue = filterValue; + m_WhereClause = null; + m_ArgumentValue = null; + m_FilterOptions = filterOptions; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + { + m_FilterValue = null; + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, MySqlLimitOption limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = limitOptions; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// TableDbCommandBuilder<MySqlCommand, MySqlParameter, MySqlLimitOption>. + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = (MySqlLimitOption)limitOptions; + return this; + } + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateObject`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateObject`1.cs index 4c8793663..e0bc1f1b6 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateObject`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateObject`1.cs @@ -3,64 +3,63 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Command object that represents an update operation. +/// +internal sealed class MySqlUpdateObject : MySqlObjectCommand + where TArgument : class { + readonly UpdateOptions m_Options; + /// - /// Command object that represents an update operation. + /// Initializes a new instance of the class. /// - internal sealed class MySqlUpdateObject : MySqlObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public MySqlUpdateObject(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue, UpdateOptions options) + : base(dataSource, tableName, argumentValue) { - readonly UpdateOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public MySqlUpdateObject(MySqlDataSourceBase dataSource, MySqlObjectName tableName, TArgument argumentValue, UpdateOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// - /// - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + m_Options = options; + } - if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) - throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// + /// + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); + if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) + throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); - var sql = new StringBuilder(); - if (m_Options.HasFlag(UpdateOptions.ReturnOldValues)) - { - sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); - sql.AppendLine(); - } - sqlBuilder.BuildUpdateByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); - if (!m_Options.HasFlag(UpdateOptions.ReturnOldValues)) - { - sql.AppendLine(); - sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); - } + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - return new MySqlCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckUpdateRowCount(m_Options); + var sql = new StringBuilder(); + if (m_Options.HasFlag(UpdateOptions.ReturnOldValues)) + { + sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); + sql.AppendLine(); } + sqlBuilder.BuildUpdateByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); + if (!m_Options.HasFlag(UpdateOptions.ReturnOldValues)) + { + sql.AppendLine(); + sqlBuilder.BuildSelectByKeyStatement(sql, Table.Name.ToQuotedString(), ";"); + } + + return new MySqlCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckUpdateRowCount(m_Options); } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateSet.cs index 45c4a04ef..54f72f927 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/CommandBuilders/MySqlUpdateSet.cs @@ -5,231 +5,230 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql.CommandBuilders +namespace Tortuga.Chain.MySql.CommandBuilders; + +/// +/// Class MySqlUpdateSet. +/// +internal sealed class MySqlUpdateSet : UpdateSetDbCommandBuilder { + readonly int? m_ExpectedRowCount; + readonly object? m_NewValues; + readonly UpdateOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly TableOrViewMetadata m_Table; + readonly object? m_UpdateArgumentValue; + readonly string? m_UpdateExpression; + FilterOptions m_FilterOptions; + object? m_FilterValue; + object? m_WhereArgumentValue; + string? m_WhereClause; + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The new values. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public MySqlUpdateSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, object? newValues, string whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_WhereClause = whereClause; + m_ExpectedRowCount = expectedRowCount; + m_Options = options; + m_Parameters = parameters; + } + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The new values. + /// The options. + /// Cannot use Key attributes with this operation. + public MySqlUpdateSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_Options = options; + } + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The update expression. + /// The update argument value. + /// The options. + /// Cannot use Key attributes with this operation. + public MySqlUpdateSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_UpdateExpression = updateExpression; + m_Options = options; + m_UpdateArgumentValue = updateArgumentValue; + } + /// - /// Class MySqlUpdateSet. + /// Applies this command to all rows. /// - internal sealed class MySqlUpdateSet : UpdateSetDbCommandBuilder + /// + public override UpdateSetDbCommandBuilder All() + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } + + public override CommandExecutionToken Prepare(Materializer materializer) { - readonly int? m_ExpectedRowCount; - readonly object? m_NewValues; - readonly UpdateOptions m_Options; - readonly IEnumerable? m_Parameters; - readonly TableOrViewMetadata m_Table; - readonly object? m_UpdateArgumentValue; - readonly string? m_UpdateExpression; - FilterOptions m_FilterOptions; - object? m_FilterValue; - object? m_WhereArgumentValue; - string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public MySqlUpdateSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, object? newValues, string whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, false); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + var sql = new StringBuilder(); + if (sqlBuilder.HasReadFields && m_Options.HasFlag(UpdateOptions.ReturnOldValues)) { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_WhereClause = whereClause; - m_ExpectedRowCount = expectedRowCount; - m_Options = options; - m_Parameters = parameters; + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, " FROM " + m_Table.Name.ToQuotedString()); + if (m_FilterValue != null) + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + sql.Append(" WHERE " + m_WhereClause); + sql.AppendLine(";"); } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The options. - /// Cannot use Key attributes with this operation. - public MySqlUpdateSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) + var parameters = new List(); + sql.Append("UPDATE " + m_Table.Name.ToQuotedString()); + if (m_UpdateExpression == null) { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_Options = options; + sqlBuilder.BuildSetClause(sql, " SET ", null, null); } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The update expression. - /// The update argument value. - /// The options. - /// Cannot use Key attributes with this operation. - public MySqlUpdateSet(MySqlDataSourceBase dataSource, MySqlObjectName tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) + else { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_UpdateExpression = updateExpression; - m_Options = options; - m_UpdateArgumentValue = updateArgumentValue; + sql.Append(" SET " + m_UpdateExpression); + parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); } - /// - /// Applies this command to all rows. - /// - /// - public override UpdateSetDbCommandBuilder All() + if (m_FilterValue != null) { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + parameters.AddRange(sqlBuilder.GetParameters()); } - - public override CommandExecutionToken Prepare(Materializer materializer) + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); + parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, false); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - var sql = new StringBuilder(); - if (sqlBuilder.HasReadFields && m_Options.HasFlag(UpdateOptions.ReturnOldValues)) - { - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, " FROM " + m_Table.Name.ToQuotedString()); - if (m_FilterValue != null) - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - sql.Append(" WHERE " + m_WhereClause); - sql.AppendLine(";"); - } - - var parameters = new List(); - sql.Append("UPDATE " + m_Table.Name.ToQuotedString()); - if (m_UpdateExpression == null) - { - sqlBuilder.BuildSetClause(sql, " SET ", null, null); - } - else - { - sql.Append(" SET " + m_UpdateExpression); - parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); - } + parameters = sqlBuilder.GetParameters(); + } + sql.AppendLine(";"); + if (sqlBuilder.HasReadFields && !m_Options.HasFlag(UpdateOptions.ReturnOldValues)) + { + sqlBuilder.BuildSelectClause(sql, "SELECT ", null, " FROM " + m_Table.Name.ToQuotedString()); if (m_FilterValue != null) - { sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - parameters.AddRange(sqlBuilder.GetParameters()); - } else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { sql.Append(" WHERE " + m_WhereClause); - parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } sql.AppendLine(";"); + } - if (sqlBuilder.HasReadFields && !m_Options.HasFlag(UpdateOptions.ReturnOldValues)) - { - sqlBuilder.BuildSelectClause(sql, "SELECT ", null, " FROM " + m_Table.Name.ToQuotedString()); - if (m_FilterValue != null) - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - sql.Append(" WHERE " + m_WhereClause); - sql.AppendLine(";"); - } + if (m_Parameters != null) + parameters.AddRange(m_Parameters); - if (m_Parameters != null) - parameters.AddRange(m_Parameters); + return new MySqlCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); + } - return new MySqlCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) - { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - return this; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause) - { - m_WhereClause = whereClause; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; - } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + return this; + } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) - { - m_WhereClause = whereClause; - m_WhereArgumentValue = argumentValue; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; - } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = argumentValue; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlCommandExecutionToken.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlCommandExecutionToken.cs index 470690634..f30d516be 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlCommandExecutionToken.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlCommandExecutionToken.cs @@ -2,18 +2,17 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class MySqlCommandExecutionToken. +/// +public class MySqlCommandExecutionToken : CommandExecutionToken { /// - /// Class MySqlCommandExecutionToken. + /// Initializes a new instance of the class. /// - public class MySqlCommandExecutionToken : CommandExecutionToken + public MySqlCommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) : base(dataSource, operationName, commandText, parameters, commandType) { - /// - /// Initializes a new instance of the class. - /// - public MySqlCommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) : base(dataSource, operationName, commandText, parameters, commandType) - { - } } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.Traits.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.Traits.cs index 4867d7f39..7897ca458 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.Traits.cs @@ -9,8 +9,8 @@ namespace Tortuga.Chain.MySql; -[UseTrait(typeof(SupportsDeleteAllTrait))] -[UseTrait(typeof(SupportsTruncateTrait))] +[UseTrait(typeof(SupportsDeleteAllTrait))] +[UseTrait(typeof(SupportsTruncateTrait))] [UseTrait(typeof(SupportsSqlQueriesTrait))] [UseTrait(typeof(SupportsInsertBatchTrait>))] @@ -27,6 +27,7 @@ namespace Tortuga.Chain.MySql; [UseTrait(typeof(SupportsInsertBulkTrait))] [UseTrait(typeof(SupportsScalarFunctionTrait))] [UseTrait(typeof(SupportsProcedureTrait))] +[UseTrait(typeof(SupportsGetByColumnListTrait))] partial class MySqlDataSourceBase : ICrudDataSource, IAdvancedCrudDataSource { DatabaseMetadataCache ICommandHelper.DatabaseMetadata => DatabaseMetadata; @@ -99,7 +100,7 @@ TableDbCommandBuilder(this, tableOrViewName, filterValue, filterOptions); } - SingleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class { string where = keyColumn.SqlName + " = @Param0"; @@ -111,12 +112,10 @@ SingleRowDbCommandBuilder IGetByKeyHelper(this, tableName, where, parameters); - } MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKeyList(AbstractObjectName tableName, ColumnMetadata keyColumn, IEnumerable keys) where TObject : class { - var keyList = keys.AsList(); string where; @@ -142,15 +141,29 @@ DbCommandBuilder IInsertBatchHelper(this, tableName, objects, options); ; } + MySqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, DataTable dataTable) + { + return new MySqlInsertBulk(this, tableName, dataTable); + } + + MySqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, IDataReader dataReader) + { + return new MySqlInsertBulk(this, tableName, dataReader); + } + ObjectDbCommandBuilder IInsertHelper.OnInsertObject(AbstractObjectName tableName, TArgument argumentValue, InsertOptions options) -where TArgument : class + where TArgument : class { return new MySqlInsertObject(this, tableName, argumentValue, options); } - MultipleRowDbCommandBuilder IUpdateDeleteByKeyHelper.OnUpdateByKeyList(AbstractObjectName tableName, TArgument newValues, IEnumerable keys, UpdateOptions options) + ObjectDbCommandBuilder IUpsertHelper.OnInsertOrUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpsertOptions options) { + return new MySqlInsertOrUpdateObject(this, tableName, argumentValue, options); + } + MultipleRowDbCommandBuilder IUpdateDeleteByKeyHelper.OnUpdateByKeyList(AbstractObjectName tableName, TArgument newValues, IEnumerable keys, UpdateOptions options) + { var primaryKeys = DatabaseMetadata.GetTableOrView(tableName).PrimaryKeyColumns; if (primaryKeys.Count != 1) throw new MappingException($"{nameof(UpdateByKeyList)} operation isn't allowed on {tableName} because it doesn't have a single primary key."); @@ -198,46 +211,25 @@ IUpdateSetDbCommandBuilder IUpdateDeleteSetH return Sql("DELETE FROM " + table.Name.ToQuotedString() + ";").AsNonQuery(); } - private partial MultipleTableDbCommandBuilder OnSql(string sqlStatement, object? argumentValue) - { - return new MySqlSqlCall(this, sqlStatement, argumentValue); - } - - private partial ILink OnTruncate(AbstractObjectName tableName) - { - //Verify the table name actually exists. - var table = DatabaseMetadata.GetTableOrView(tableName); - return Sql("TRUNCATE TABLE " + table.Name.ToQuotedString() + ";").AsNonQuery(); - } - - ObjectDbCommandBuilder IUpsertHelper.OnInsertOrUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpsertOptions options) - { - return new MySqlInsertOrUpdateObject(this, tableName, argumentValue, options); - } - - - MySqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, DataTable dataTable) + private partial ProcedureDbCommandBuilder OnProcedure(AbstractObjectName procedureName, object? argumentValue) { - return new MySqlInsertBulk(this, tableName, dataTable); + return new AbstractProcedureCall(this, procedureName, argumentValue); } - MySqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, IDataReader dataReader) + private partial ScalarDbCommandBuilder OnScalarFunction(AbstractObjectName scalarFunctionName, object? argumentValue) { - return new MySqlInsertBulk(this, tableName, dataReader); + return new AbstractScalarFunction(this, scalarFunctionName, argumentValue); } - private partial ProcedureDbCommandBuilder OnProcedure(AbstractObjectName procedureName, object? argumentValue) + private partial MultipleTableDbCommandBuilder OnSql(string sqlStatement, object? argumentValue) { - return new AbstractProcedureCall(this, procedureName, argumentValue); + return new MySqlSqlCall(this, sqlStatement, argumentValue); } - private partial ScalarDbCommandBuilder OnScalarFunction(AbstractObjectName scalarFunctionName, object? argumentValue) + private partial ILink OnTruncate(AbstractObjectName tableName) { - return new AbstractScalarFunction(this, scalarFunctionName, argumentValue); + //Verify the table name actually exists. + var table = DatabaseMetadata.GetTableOrView(tableName); + return Sql("TRUNCATE TABLE " + table.Name.ToQuotedString() + ";").AsNonQuery(); } - } - - - - diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.cs index 9ff80e70e..ee45b2f2b 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceBase.cs @@ -2,30 +2,29 @@ using Tortuga.Chain.DataSources; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class MySqlDataSourceBase. +/// +public abstract partial class MySqlDataSourceBase : DataSource { /// - /// Class MySqlDataSourceBase. + /// Initializes a new instance of the class. /// - public abstract partial class MySqlDataSourceBase : DataSource + /// Optional settings object. + protected MySqlDataSourceBase(DataSourceSettings? settings) : base(settings) { - /// - /// Initializes a new instance of the class. - /// - /// Optional settings object. - protected MySqlDataSourceBase(DataSourceSettings? settings) : base(settings) - { - } + } - /// - /// Gets the database metadata. - /// - public abstract new MySqlMetadataCache DatabaseMetadata { get; } + /// + /// Gets the database metadata. + /// + public abstract new MySqlMetadataCache DatabaseMetadata { get; } - /// - /// Called when Database.DatabaseMetadata is invoked. - /// - /// - protected override IDatabaseMetadataCache OnGetDatabaseMetadata() => DatabaseMetadata; - } + /// + /// Called when Database.DatabaseMetadata is invoked. + /// + /// + protected override IDatabaseMetadataCache OnGetDatabaseMetadata() => DatabaseMetadata; } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceSettings.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceSettings.cs index 25e8fc446..fc76a16fb 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceSettings.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlDataSourceSettings.cs @@ -1,27 +1,26 @@ using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class MySqlDataSourceSettings. +/// +/// +public class MySqlDataSourceSettings : DataSourceSettings { /// - /// Class MySqlDataSourceSettings. + /// Initializes a new instance of the class. /// - /// - public class MySqlDataSourceSettings : DataSourceSettings - { - /// - /// Initializes a new instance of the class. - /// - public MySqlDataSourceSettings() { } + public MySqlDataSourceSettings() { } - internal MySqlDataSourceSettings(MySqlDataSource dataSource, bool forwardEvents = false) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + internal MySqlDataSourceSettings(MySqlDataSource dataSource, bool forwardEvents = false) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - DefaultCommandTimeout = dataSource.DefaultCommandTimeout; - StrictMode = dataSource.StrictMode; - SequentialAccessMode = dataSource.SequentialAccessMode; - SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; - } + DefaultCommandTimeout = dataSource.DefaultCommandTimeout; + StrictMode = dataSource.StrictMode; + SequentialAccessMode = dataSource.SequentialAccessMode; + SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlMetadataCache.cs index 1777f97f0..e5a621bf7 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlMetadataCache.cs @@ -5,789 +5,788 @@ using Tortuga.Chain.Metadata; using Tortuga.Chain.SqlServer; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class MySqlMetadataCache. +/// +public class MySqlMetadataCache : DatabaseMetadataCache { + private readonly MySqlConnectionStringBuilder m_ConnectionBuilder; + private readonly ConcurrentDictionary> m_ScalarFunctions = new(); + private readonly ConcurrentDictionary> m_StoredProcedures = new(); + private readonly ConcurrentDictionary> m_Tables = new(); + private readonly ConcurrentDictionary<(Type, OperationType), DatabaseObject> m_TypeTableMap = new(); + private string? m_DefaultSchema; + /// - /// Class MySqlMetadataCache. + /// Initializes a new instance of the class. /// - public class MySqlMetadataCache : DatabaseMetadataCache + /// The connection builder. + public MySqlMetadataCache(MySqlConnectionStringBuilder connectionBuilder) { - private readonly MySqlConnectionStringBuilder m_ConnectionBuilder; - private readonly ConcurrentDictionary> m_ScalarFunctions = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary> m_StoredProcedures = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary> m_Tables = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary<(Type, OperationType), DatabaseObject> m_TypeTableMap = new ConcurrentDictionary<(Type, OperationType), DatabaseObject>(); - private string? m_DefaultSchema; - - /// - /// Initializes a new instance of the class. - /// - /// The connection builder. - public MySqlMetadataCache(MySqlConnectionStringBuilder connectionBuilder) - { - m_ConnectionBuilder = connectionBuilder; - } + m_ConnectionBuilder = connectionBuilder; + } - /// - /// Returns the user's default schema. - /// - /// - public string DefaultSchema + /// + /// Returns the user's default schema. + /// + /// + public string DefaultSchema + { + get { - get + if (m_DefaultSchema == null) { - if (m_DefaultSchema == null) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new MySqlCommand("SELECT Database()", con)) { - con.Open(); - using (var cmd = new MySqlCommand("SELECT Database()", con)) - { - m_DefaultSchema = (string)cmd.ExecuteScalar()!; - } + m_DefaultSchema = (string)cmd.ExecuteScalar()!; } } - return m_DefaultSchema; } + return m_DefaultSchema; } + } - /// - /// Gets the indexes for a table. - /// - /// Name of the table. - /// - /// - /// This should be cached on a TableOrViewMetadata object. - /// - public override IndexMetadataCollection GetIndexesForTable(MySqlObjectName tableName) - { - var table = GetTableOrView(tableName); - var results = new List>(); + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + /// https://stackoverflow.com/a/6582902/5274 + public override int? MaxParameters => 65535; - var scratch = new List(); + /// + /// Gets the indexes for a table. + /// + /// Name of the table. + /// + /// + /// This should be cached on a TableOrViewMetadata object. + /// + public override IndexMetadataCollection GetIndexesForTable(MySqlObjectName tableName) + { + var table = GetTableOrView(tableName); + var results = new List>(); - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) - using (var con2 = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + var scratch = new List(); + + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con2 = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + con2.Open(); + using (var cmd = new MySqlCommand("SHOW INDEXES FROM " + table.Name.ToQuotedString(), con)) + using (var reader = cmd.ExecuteReader()) { - con.Open(); - con2.Open(); - using (var cmd = new MySqlCommand("SHOW INDEXES FROM " + table.Name.ToQuotedString(), con)) - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) + scratch.Add(new IndexTemp() { - scratch.Add(new IndexTemp() - { - IndexName = reader.GetString("Key_name"), - Order = reader.GetInt32("Seq_in_index"), - ColumnName = reader.GetString("Column_name"), - Collation = reader.GetStringOrNull("Collation"), - IndexType = reader.GetString("Index_type"), - NonUnique = reader.GetBoolean("Non_unique") - }); - } + IndexName = reader.GetString("Key_name"), + Order = reader.GetInt32("Seq_in_index"), + ColumnName = reader.GetString("Column_name"), + Collation = reader.GetStringOrNull("Collation"), + IndexType = reader.GetString("Index_type"), + NonUnique = reader.GetBoolean("Non_unique") + }); } } + } - var indexNames = scratch.Select(x => x.IndexName).Distinct(); - foreach (var indexName in indexNames) - { - var isPrimaryKey = (indexName == "PRIMARY"); - var indexColumns = scratch.Where(x => x.IndexName == indexName).OrderBy(x => x.Order).Select(x => new IndexColumnMetadata(table.Columns[x.ColumnName], x.Collation == "D", x.Collation == null)).ToList(); - - var isUnique = scratch.First(x => x.IndexName == indexName).NonUnique; - var indexTypeName = scratch.First(x => x.IndexName == indexName).IndexType; - IndexType indexType; - switch (indexTypeName) - { - case "BTREE": indexType = IndexType.BTree; break; - case "HASH": indexType = IndexType.Hash; break; - case "RTREE": indexType = IndexType.RTree; break; - case "FULLTEXT": indexType = IndexType.FullText; break; - default: indexType = IndexType.Unknown; break; - } + var indexNames = scratch.Select(x => x.IndexName).Distinct(); + foreach (var indexName in indexNames) + { + var isPrimaryKey = (indexName == "PRIMARY"); + var indexColumns = scratch.Where(x => x.IndexName == indexName).OrderBy(x => x.Order).Select(x => new IndexColumnMetadata(table.Columns[x.ColumnName], x.Collation == "D", x.Collation == null)).ToList(); - results.Add(new IndexMetadata(table.Name, indexName, isPrimaryKey, isUnique, false, new IndexColumnMetadataCollection(indexColumns), null, null, indexType)); + var isUnique = scratch.First(x => x.IndexName == indexName).NonUnique; + var indexTypeName = scratch.First(x => x.IndexName == indexName).IndexType; + IndexType indexType; + switch (indexTypeName) + { + case "BTREE": indexType = IndexType.BTree; break; + case "HASH": indexType = IndexType.Hash; break; + case "RTREE": indexType = IndexType.RTree; break; + case "FULLTEXT": indexType = IndexType.FullText; break; + default: indexType = IndexType.Unknown; break; } - return new IndexMetadataCollection(results); + results.Add(new IndexMetadata(table.Name, indexName, isPrimaryKey, isUnique, false, new IndexColumnMetadataCollection(indexColumns), null, null, indexType)); } - /// - /// Gets the metadata for a scalar function. - /// - /// Name of the scalar function. - /// Null if the object could not be found. - public override ScalarFunctionMetadata GetScalarFunction(MySqlObjectName scalarFunctionName) - { - return m_ScalarFunctions.GetOrAdd(scalarFunctionName, GetScalarFunctionInternal); - } + return new IndexMetadataCollection(results); + } - /// - /// Gets the scalar functions that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetScalarFunctions() - { - return m_ScalarFunctions.GetValues(); - } + /// + /// Gets the metadata for a scalar function. + /// + /// Name of the scalar function. + /// Null if the object could not be found. + public override ScalarFunctionMetadata GetScalarFunction(MySqlObjectName scalarFunctionName) + { + return m_ScalarFunctions.GetOrAdd(scalarFunctionName, GetScalarFunctionInternal); + } - /// - /// Gets the stored procedure's metadata. - /// - /// Name of the procedure. - /// - /// - public override StoredProcedureMetadata GetStoredProcedure(MySqlObjectName procedureName) - { - return m_StoredProcedures.GetOrAdd(procedureName, GetStoredProcedureInteral); - } + /// + /// Gets the scalar functions that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetScalarFunctions() + { + return m_ScalarFunctions.GetValues(); + } - /// - /// Gets the stored procedures that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetStoredProcedures() - { - return m_StoredProcedures.GetValues(); - } + /// + /// Gets the stored procedure's metadata. + /// + /// Name of the procedure. + /// + /// + public override StoredProcedureMetadata GetStoredProcedure(MySqlObjectName procedureName) + { + return m_StoredProcedures.GetOrAdd(procedureName, GetStoredProcedureInteral); + } - /// - /// Gets the metadata for a table. - /// - /// Name of the table. - /// TableOrViewMetadata<MySqlObjectName, MySqlDbType>. - public override TableOrViewMetadata GetTableOrView(MySqlObjectName tableName) - { - return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); - } + /// + /// Gets the stored procedures that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetStoredProcedures() + { + return m_StoredProcedures.GetValues(); + } - /// - /// Gets the tables and views that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetTablesAndViews() - { - return m_Tables.GetValues(); - } + /// + /// Gets the metadata for a table. + /// + /// Name of the table. + /// TableOrViewMetadata<MySqlObjectName, MySqlDbType>. + public override TableOrViewMetadata GetTableOrView(MySqlObjectName tableName) + { + return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); + } - /// - /// Preloads all of the metadata for this data source. - /// - public override void Preload() - { - PreloadTables(); - PreloadViews(); - PreloadScalarFunctions(); - PreloadStoredProcedures(); - } + /// + /// Gets the tables and views that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetTablesAndViews() + { + return m_Tables.GetValues(); + } - /// - /// Preloads the scalar functions. - /// - public void PreloadScalarFunctions() - { - const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION'"; + /// + /// Preloads all of the metadata for this data source. + /// + public override void Preload() + { + PreloadTables(); + PreloadViews(); + PreloadScalarFunctions(); + PreloadStoredProcedures(); + } - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + /// + /// Preloads the scalar functions. + /// + public void PreloadScalarFunctions() + { + const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION'"; + + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(sql, con)) { - con.Open(); - using (var cmd = new MySqlCommand(sql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString(0); - var name = reader.GetString(1); - GetScalarFunction(new MySqlObjectName(schema, name)); - } + var schema = reader.GetString(0); + var name = reader.GetString(1); + GetScalarFunction(new MySqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the table value functions. - /// - public void PreloadStoredProcedures() - { - const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE'"; + /// + /// Preloads the table value functions. + /// + public void PreloadStoredProcedures() + { + const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE'"; - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(sql, con)) { - con.Open(); - using (var cmd = new MySqlCommand(sql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString(0); - var name = reader.GetString(1); - GetStoredProcedure(new MySqlObjectName(schema, name)); - } + var schema = reader.GetString(0); + var name = reader.GetString(1); + GetStoredProcedure(new MySqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the metadata for all tables. - /// - public void PreloadTables() - { - const string tableList = "SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.Tables WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA <> 'mysql' AND TABLE_SCHEMA <> 'mysql' AND TABLE_SCHEMA <> 'performance_schema' AND TABLE_SCHEMA <> 'sys'"; + /// + /// Preloads the metadata for all tables. + /// + public void PreloadTables() + { + const string tableList = "SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.Tables WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA <> 'mysql' AND TABLE_SCHEMA <> 'mysql' AND TABLE_SCHEMA <> 'performance_schema' AND TABLE_SCHEMA <> 'sys'"; - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(tableList, con)) { - con.Open(); - using (var cmd = new MySqlCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString(0); - var name = reader.GetString(1); - GetTableOrView(new MySqlObjectName(schema, name)); - } + var schema = reader.GetString(0); + var name = reader.GetString(1); + GetTableOrView(new MySqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the metadata for all views. - /// - public void PreloadViews() - { - const string tableList = "SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.Tables WHERE TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA <> 'sys';"; + /// + /// Preloads the metadata for all views. + /// + public void PreloadViews() + { + const string tableList = "SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.Tables WHERE TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA <> 'sys';"; - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(tableList, con)) { - con.Open(); - using (var cmd = new MySqlCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString(0); - var name = reader.GetString(1); - GetTableOrView(new MySqlObjectName(schema, name)); - } + var schema = reader.GetString(0); + var name = reader.GetString(1); + GetTableOrView(new MySqlObjectName(schema, name)); } } } } + } - /// - /// Resets the metadata cache, clearing out all cached metadata. - /// - public override void Reset() - { - m_StoredProcedures.Clear(); - m_ScalarFunctions.Clear(); - m_Tables.Clear(); - m_TypeTableMap.Clear(); - m_DefaultSchema = null; - } + /// + /// Resets the metadata cache, clearing out all cached metadata. + /// + public override void Reset() + { + m_StoredProcedures.Clear(); + m_ScalarFunctions.Clear(); + m_Tables.Clear(); + m_TypeTableMap.Clear(); + m_DefaultSchema = null; + } - /// - /// Converts a value to a string suitable for use in a SQL statement. - /// - /// The value. - /// Optional database column type. - /// - public override string ValueToSqlValue(object value, MySqlDbType? dbType) + /// + /// Converts a value to a string suitable for use in a SQL statement. + /// + /// The value. + /// Optional database column type. + /// + public override string ValueToSqlValue(object value, MySqlDbType? dbType) + { + switch (value) { - switch (value) - { - case string s: - { - var result = new System.Text.StringBuilder((int)(s.Length * 1.1)); + case string s: + { + var result = new System.Text.StringBuilder((int)(s.Length * 1.1)); - foreach (var c in s) + foreach (var c in s) + { + switch (c) { - switch (c) - { - case '\'': - result.Append(@"\'"); - break; - - case '\"': - result.Append(@"\"""); - break; - - case '\b': - result.Append(@"\b"); - break; - - case '\n': - result.Append(@"\n"); - break; - - case '\r': - result.Append(@"\r"); - break; - - case '\t': - result.Append(@"\t"); - break; - - case '\\': - result.Append(@"\\"); - break; - - default: - result.Append(c); - break; - } - } + case '\'': + result.Append(@"\'"); + break; + + case '\"': + result.Append(@"\"""); + break; + + case '\b': + result.Append(@"\b"); + break; + + case '\n': + result.Append(@"\n"); + break; + + case '\r': + result.Append(@"\r"); + break; - return "'" + result + "'"; + case '\t': + result.Append(@"\t"); + break; + + case '\\': + result.Append(@"\\"); + break; + + default: + result.Append(c); + break; + } } - default: - return base.ValueToSqlValue(value, dbType); - } - } + return "'" + result + "'"; + } - /// - /// Parse a string and return the database specific representation of the object name. - /// - /// The schema. - /// The name. - /// MySqlObjectName. - protected override MySqlObjectName ParseObjectName(string? schema, string name) - { - if (schema == null) - return new MySqlObjectName(name); - return new MySqlObjectName(schema, name); + default: + return base.ValueToSqlValue(value, dbType); } + } + + /// + /// Parse a string and return the database specific representation of the object name. + /// + /// The schema. + /// The name. + /// MySqlObjectName. + protected override MySqlObjectName ParseObjectName(string? schema, string name) + { + if (schema == null) + return new MySqlObjectName(name); + return new MySqlObjectName(schema, name); + } - /// - /// Determines the database column type from the column type name. - /// - /// Name of the database column type. - /// Indicates whether or not the column is unsigned. Only applicable to some databases. - /// - /// This does not honor registered types. This is only used for the database's hard-coded list of native types. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - protected override MySqlDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned) + /// + /// Determines the database column type from the column type name. + /// + /// Name of the database column type. + /// Indicates whether or not the column is unsigned. Only applicable to some databases. + /// + /// This does not honor registered types. This is only used for the database's hard-coded list of native types. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + protected override MySqlDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned) + { + if (string.IsNullOrEmpty(typeName)) + return null; + + switch (typeName.ToUpperInvariant()) { - if (string.IsNullOrEmpty(typeName)) + case "INT1": + case "BOOL": + case "BOOLEAN": + case "TINYINT": if (isUnsigned == true) return MySqlDbType.UByte; else return MySqlDbType.Byte; + case "INT2": + case "SMALLINT": if (isUnsigned == true) return MySqlDbType.UInt16; else return MySqlDbType.Int16; + case "INT3": + case "MIDDLEINT": + case "MEDIUMINT": if (isUnsigned == true) return MySqlDbType.UInt24; else return MySqlDbType.Int24; + case "INT4": + case "INTEGER": + case "INT": if (isUnsigned == true) return MySqlDbType.UInt32; else return MySqlDbType.Int32; + case "INT8": + case "BIGINT": if (isUnsigned == true) return MySqlDbType.UInt64; else return MySqlDbType.Int64; + case "FIXED": + case "NUMERIC": + case "DECIMAL": return MySqlDbType.Decimal; + case "FLOAT4": + case "FLOAT": return MySqlDbType.Float; + case "DOUBLE PRECISION": + case "REAL": + case "FLOAT8": + case "DOUBLE": return MySqlDbType.Double; + case "BIT": return MySqlDbType.Bit; + case "DATE": return MySqlDbType.Date; + case "TIME": return MySqlDbType.Time; + case "DATETIME": return MySqlDbType.DateTime; + case "TIMESTAMP": return MySqlDbType.Timestamp; + case "YEAR": return MySqlDbType.Year; + case "CHAR": return MySqlDbType.VarChar; + case "CHARACTER VARYING": + case "VARCHAR": return MySqlDbType.VarChar; + case "BINARY": return MySqlDbType.Binary; + case "VARBINARY": return MySqlDbType.VarBinary; + case "BLOB": return MySqlDbType.Blob; + case "TEXT": return MySqlDbType.Text; + case "ENUM": return MySqlDbType.Enum; + case "SET": return MySqlDbType.Set; + case "GEOMETRY": return MySqlDbType.Geometry; + case "POINT": return MySqlDbType.Geometry; + case "LINESTRING": return MySqlDbType.Geometry; + case "POLYGON": return MySqlDbType.Geometry; + case "MULTIPOINT": return MySqlDbType.Geometry; + case "MULTILINESTRING": return MySqlDbType.Geometry; + case "MULTIPOLYGON": return MySqlDbType.Geometry; + case "GEOMETRYCOLLECTION": return MySqlDbType.Geometry; + case "JSON": return MySqlDbType.JSON; + case "TINYBLOB": return MySqlDbType.TinyBlob; + case "LONG VARBINARY": + case "MEDIUMBLOB": return MySqlDbType.MediumBlob; + case "LONGBLOB": return MySqlDbType.LongBlob; + case "TINYTEXT": return MySqlDbType.TinyText; + case "LONG VARCHAR": + case "MEDIUMTEXT": return MySqlDbType.MediumText; + case "LONGTEXT": return MySqlDbType.LongText; + default: return null; - - switch (typeName.ToUpperInvariant()) - { - case "INT1": - case "BOOL": - case "BOOLEAN": - case "TINYINT": if (isUnsigned == true) return MySqlDbType.UByte; else return MySqlDbType.Byte; - case "INT2": - case "SMALLINT": if (isUnsigned == true) return MySqlDbType.UInt16; else return MySqlDbType.Int16; - case "INT3": - case "MIDDLEINT": - case "MEDIUMINT": if (isUnsigned == true) return MySqlDbType.UInt24; else return MySqlDbType.Int24; - case "INT4": - case "INTEGER": - case "INT": if (isUnsigned == true) return MySqlDbType.UInt32; else return MySqlDbType.Int32; - case "INT8": - case "BIGINT": if (isUnsigned == true) return MySqlDbType.UInt64; else return MySqlDbType.Int64; - case "FIXED": - case "NUMERIC": - case "DECIMAL": return MySqlDbType.Decimal; - case "FLOAT4": - case "FLOAT": return MySqlDbType.Float; - case "DOUBLE PRECISION": - case "REAL": - case "FLOAT8": - case "DOUBLE": return MySqlDbType.Double; - case "BIT": return MySqlDbType.Bit; - case "DATE": return MySqlDbType.Date; - case "TIME": return MySqlDbType.Time; - case "DATETIME": return MySqlDbType.DateTime; - case "TIMESTAMP": return MySqlDbType.Timestamp; - case "YEAR": return MySqlDbType.Year; - case "CHAR": return MySqlDbType.VarChar; - case "CHARACTER VARYING": - case "VARCHAR": return MySqlDbType.VarChar; - case "BINARY": return MySqlDbType.Binary; - case "VARBINARY": return MySqlDbType.VarBinary; - case "BLOB": return MySqlDbType.Blob; - case "TEXT": return MySqlDbType.Text; - case "ENUM": return MySqlDbType.Enum; - case "SET": return MySqlDbType.Set; - case "GEOMETRY": return MySqlDbType.Geometry; - case "POINT": return MySqlDbType.Geometry; - case "LINESTRING": return MySqlDbType.Geometry; - case "POLYGON": return MySqlDbType.Geometry; - case "MULTIPOINT": return MySqlDbType.Geometry; - case "MULTILINESTRING": return MySqlDbType.Geometry; - case "MULTIPOLYGON": return MySqlDbType.Geometry; - case "GEOMETRYCOLLECTION": return MySqlDbType.Geometry; - case "JSON": return MySqlDbType.JSON; - case "TINYBLOB": return MySqlDbType.TinyBlob; - case "LONG VARBINARY": - case "MEDIUMBLOB": return MySqlDbType.MediumBlob; - case "LONGBLOB": return MySqlDbType.LongBlob; - case "TINYTEXT": return MySqlDbType.TinyText; - case "LONG VARCHAR": - case "MEDIUMTEXT": return MySqlDbType.MediumText; - case "LONGTEXT": return MySqlDbType.LongText; - default: - return null; - } } + } - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Type of the database column. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. Defaults to string. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// This does not take into consideration registered types. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - protected override Type? ToClrType(MySqlDbType dbType, bool isNullable, int? maxLength) + /// + /// Returns the CLR type that matches the indicated database column type. + /// + /// Type of the database column. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. Defaults to string. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// This does not take into consideration registered types. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + protected override Type? ToClrType(MySqlDbType dbType, bool isNullable, int? maxLength) + { + switch (dbType) { - switch (dbType) - { - case MySqlDbType.Bit: - case MySqlDbType.Bool: - return isNullable ? typeof(bool?) : typeof(bool); + case MySqlDbType.Bit: + case MySqlDbType.Bool: + return isNullable ? typeof(bool?) : typeof(bool); - case MySqlDbType.Decimal: - case MySqlDbType.NewDecimal: - return isNullable ? typeof(decimal?) : typeof(decimal); + case MySqlDbType.Decimal: + case MySqlDbType.NewDecimal: + return isNullable ? typeof(decimal?) : typeof(decimal); - case MySqlDbType.Byte: - return isNullable ? typeof(sbyte?) : typeof(sbyte); + case MySqlDbType.Byte: + return isNullable ? typeof(sbyte?) : typeof(sbyte); - case MySqlDbType.Int16: - return isNullable ? typeof(short?) : typeof(short); + case MySqlDbType.Int16: + return isNullable ? typeof(short?) : typeof(short); - case MySqlDbType.Int32: - return isNullable ? typeof(int?) : typeof(int); + case MySqlDbType.Int32: + return isNullable ? typeof(int?) : typeof(int); - case MySqlDbType.Float: - return isNullable ? typeof(float?) : typeof(float); + case MySqlDbType.Float: + return isNullable ? typeof(float?) : typeof(float); - case MySqlDbType.Double: - return isNullable ? typeof(double?) : typeof(double); + case MySqlDbType.Double: + return isNullable ? typeof(double?) : typeof(double); - case MySqlDbType.Timestamp: - case MySqlDbType.Date: - case MySqlDbType.DateTime: - case MySqlDbType.Newdate: - return isNullable ? typeof(DateTime?) : typeof(DateTime); + case MySqlDbType.Timestamp: + case MySqlDbType.Date: + case MySqlDbType.DateTime: + case MySqlDbType.Newdate: + return isNullable ? typeof(DateTime?) : typeof(DateTime); - case MySqlDbType.Int64: - return isNullable ? typeof(long?) : typeof(long); + case MySqlDbType.Int64: + return isNullable ? typeof(long?) : typeof(long); - case MySqlDbType.Int24: - return isNullable ? typeof(int?) : typeof(int); + case MySqlDbType.Int24: + return isNullable ? typeof(int?) : typeof(int); - case MySqlDbType.Time: - return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); + case MySqlDbType.Time: + return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); - case MySqlDbType.Year: - return isNullable ? typeof(sbyte?) : typeof(sbyte); + case MySqlDbType.Year: + return isNullable ? typeof(sbyte?) : typeof(sbyte); - case MySqlDbType.VarString: - case MySqlDbType.JSON: - case MySqlDbType.VarChar: - case MySqlDbType.TinyText: - case MySqlDbType.MediumText: - case MySqlDbType.LongText: - case MySqlDbType.Text: - case MySqlDbType.String: - return (maxLength == 1) ? (isNullable ? typeof(char?) : typeof(char)) : typeof(string); + case MySqlDbType.VarString: + case MySqlDbType.JSON: + case MySqlDbType.VarChar: + case MySqlDbType.TinyText: + case MySqlDbType.MediumText: + case MySqlDbType.LongText: + case MySqlDbType.Text: + case MySqlDbType.String: + return (maxLength == 1) ? (isNullable ? typeof(char?) : typeof(char)) : typeof(string); - case MySqlDbType.UByte: - return isNullable ? typeof(byte?) : typeof(byte); + case MySqlDbType.UByte: + return isNullable ? typeof(byte?) : typeof(byte); - case MySqlDbType.UInt16: - return isNullable ? typeof(ushort?) : typeof(ushort); + case MySqlDbType.UInt16: + return isNullable ? typeof(ushort?) : typeof(ushort); - case MySqlDbType.UInt32: - return isNullable ? typeof(uint?) : typeof(uint); + case MySqlDbType.UInt32: + return isNullable ? typeof(uint?) : typeof(uint); - case MySqlDbType.UInt64: - return isNullable ? typeof(ulong?) : typeof(ulong); + case MySqlDbType.UInt64: + return isNullable ? typeof(ulong?) : typeof(ulong); - case MySqlDbType.UInt24: - return isNullable ? typeof(uint?) : typeof(uint); + case MySqlDbType.UInt24: + return isNullable ? typeof(uint?) : typeof(uint); - case MySqlDbType.Binary: - case MySqlDbType.VarBinary: - return typeof(byte[]); + case MySqlDbType.Binary: + case MySqlDbType.VarBinary: + return typeof(byte[]); - case MySqlDbType.Guid: - return isNullable ? typeof(Guid?) : typeof(Guid); + case MySqlDbType.Guid: + return isNullable ? typeof(Guid?) : typeof(Guid); - case MySqlDbType.Enum: - case MySqlDbType.Set: - case MySqlDbType.TinyBlob: - case MySqlDbType.MediumBlob: - case MySqlDbType.LongBlob: - case MySqlDbType.Blob: - case MySqlDbType.Geometry: - case MySqlDbType.Null: - return null; - } + case MySqlDbType.Enum: + case MySqlDbType.Set: + case MySqlDbType.TinyBlob: + case MySqlDbType.MediumBlob: + case MySqlDbType.LongBlob: + case MySqlDbType.Blob: + case MySqlDbType.Geometry: + case MySqlDbType.Null: + return null; + } - return null; + return null; + } + + /// + /// Gets the columns. + /// + /// The schema. + /// Name of the table. + /// WARNING: Only call this with verified table names. Otherwise a SQL injection attack can occur. + private ColumnMetadataCollection GetColumns(string schema, string tableName) + { + const string ColumnSql = @"SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, COLUMN_TYPE, COLUMN_KEY, EXTRA, COLUMN_COMMENT, COLLATION_NAME FROM INFORMATION_SCHEMA.Columns WHERE TABLE_SCHEMA = @Schema AND TABLE_NAME = @Name"; + + var columns = new List>(); + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(ColumnSql, con)) + { + cmd.Parameters.AddWithValue("@Schema", schema); + cmd.Parameters.AddWithValue("@Name", tableName); + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var name = reader.GetString("COLUMN_NAME"); + //var @default = reader.GetStringOrNull("COLUMN_DEFAULT"); #226 + var isNullable = string.Equals(reader.GetString("IS_NULLABLE"), "YES", StringComparison.Ordinal); + var typeName = reader.GetString("DATA_TYPE"); + var maxLength = reader.GetUInt64OrNull("CHARACTER_MAXIMUM_LENGTH"); + var precisionA = reader.GetInt32OrNull("NUMERIC_PRECISION"); + var scale = reader.GetInt32OrNull("NUMERIC_SCALE"); + var precisionB = reader.GetInt32OrNull("DATETIME_PRECISION"); + var precision = precisionA ?? precisionB; + var fullTypeName = reader.GetString("COLUMN_TYPE"); + var key = reader.GetString("COLUMN_KEY"); + var extra = reader.GetString("EXTRA"); + //var comment = reader.GetString("COLUMN_COMMENT"); #224 + //var collation = reader.GetStringOrNull("COLLATION_NAME"); #225 + + var computed = extra.Contains("VIRTUAL"); + var primary = key.Contains("PRI"); + var isIdentity = extra.Contains("auto_increment"); + var isUnsigned = fullTypeName.Contains("unsigned"); + + var dbType = SqlTypeNameToDbType(typeName, isUnsigned); + + columns.Add(new ColumnMetadata(name, computed, primary, isIdentity, typeName, dbType, "`" + name + "`", isNullable, (int?)maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, (int?)maxLength, isUnsigned))); + } + } + } } + return new ColumnMetadataCollection((new MySqlObjectName(schema, tableName)).ToString(), columns); + } - /// - /// Gets the columns. - /// - /// The schema. - /// Name of the table. - /// WARNING: Only call this with verified table names. Otherwise a SQL injection attack can occur. - private ColumnMetadataCollection GetColumns(string schema, string tableName) + private ParameterMetadataCollection GetParameters(string schemaName, string specificName) + { + try { - const string ColumnSql = @"SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, COLUMN_TYPE, COLUMN_KEY, EXTRA, COLUMN_COMMENT, COLLATION_NAME FROM INFORMATION_SCHEMA.Columns WHERE TABLE_SCHEMA = @Schema AND TABLE_NAME = @Name"; + const string ParameterSql = "SELECT PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, DTD_IDENTIFIER FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_SCHEMA = @Schema AND SPECIFIC_NAME = @SpecificName AND PARAMETER_NAME IS NOT NULL"; + + //we exclude parameter_id 0 because it is the return type of scalar functions. + + var parameters = new List>(); - var columns = new List>(); using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) { con.Open(); - using (var cmd = new MySqlCommand(ColumnSql, con)) + + using (var cmd = new MySqlCommand(ParameterSql, con)) { - cmd.Parameters.AddWithValue("@Schema", schema); - cmd.Parameters.AddWithValue("@Name", tableName); + cmd.Parameters.AddWithValue("@Schema", schemaName); + cmd.Parameters.AddWithValue("@SpecificName", specificName); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { - var name = reader.GetString("COLUMN_NAME"); - //var @default = reader.GetStringOrNull("COLUMN_DEFAULT"); #226 - var isNullable = string.Equals(reader.GetString("IS_NULLABLE"), "YES", StringComparison.Ordinal); + var name = reader.GetString("PARAMETER_NAME"); var typeName = reader.GetString("DATA_TYPE"); + bool isNullable = true; var maxLength = reader.GetUInt64OrNull("CHARACTER_MAXIMUM_LENGTH"); var precisionA = reader.GetInt32OrNull("NUMERIC_PRECISION"); var scale = reader.GetInt32OrNull("NUMERIC_SCALE"); var precisionB = reader.GetInt32OrNull("DATETIME_PRECISION"); var precision = precisionA ?? precisionB; - var fullTypeName = reader.GetString("COLUMN_TYPE"); - var key = reader.GetString("COLUMN_KEY"); - var extra = reader.GetString("EXTRA"); - //var comment = reader.GetString("COLUMN_COMMENT"); #224 - //var collation = reader.GetStringOrNull("COLLATION_NAME"); #225 - - var computed = extra.Contains("VIRTUAL"); - var primary = key.Contains("PRI"); - var isIdentity = extra.Contains("auto_increment"); - var isUnsigned = fullTypeName.Contains("unsigned"); + var fullTypeName = reader.GetString("DTD_IDENTIFIER"); + var isUnsigned = fullTypeName.Contains("unsigned"); var dbType = SqlTypeNameToDbType(typeName, isUnsigned); - columns.Add(new ColumnMetadata(name, computed, primary, isIdentity, typeName, dbType, "`" + name + "`", isNullable, (int?)maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, (int?)maxLength, isUnsigned))); + //TASK-383: OUTPUT Parameters for MySQL + var direction = ParameterDirection.Input; + + parameters.Add(new ParameterMetadata(name, name, typeName, dbType, isNullable, (int?)maxLength, precision, scale, fullTypeName, direction)); } } } } - return new ColumnMetadataCollection((new MySqlObjectName(schema, tableName)).ToString(), columns); + return new ParameterMetadataCollection((new MySqlObjectName(schemaName, specificName)).ToString(), parameters); } - - private ParameterMetadataCollection GetParameters(string schemaName, string specificName) + catch (Exception ex) { - try - { - const string ParameterSql = "SELECT PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, DTD_IDENTIFIER FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_SCHEMA = @Schema AND SPECIFIC_NAME = @SpecificName AND PARAMETER_NAME IS NOT NULL"; - - //we exclude parameter_id 0 because it is the return type of scalar functions. - - var parameters = new List>(); - - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); - - using (var cmd = new MySqlCommand(ParameterSql, con)) - { - cmd.Parameters.AddWithValue("@Schema", schemaName); - cmd.Parameters.AddWithValue("@SpecificName", specificName); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - var name = reader.GetString("PARAMETER_NAME"); - var typeName = reader.GetString("DATA_TYPE"); - bool isNullable = true; - var maxLength = reader.GetUInt64OrNull("CHARACTER_MAXIMUM_LENGTH"); - var precisionA = reader.GetInt32OrNull("NUMERIC_PRECISION"); - var scale = reader.GetInt32OrNull("NUMERIC_SCALE"); - var precisionB = reader.GetInt32OrNull("DATETIME_PRECISION"); - var precision = precisionA ?? precisionB; - var fullTypeName = reader.GetString("DTD_IDENTIFIER"); - - var isUnsigned = fullTypeName.Contains("unsigned"); - var dbType = SqlTypeNameToDbType(typeName, isUnsigned); - - //TASK-383: OUTPUT Parameters for MySQL - var direction = ParameterDirection.Input; - - parameters.Add(new ParameterMetadata(name, name, typeName, dbType, isNullable, (int?)maxLength, precision, scale, fullTypeName, direction)); - } - } - } - } - return new ParameterMetadataCollection((new MySqlObjectName(schemaName, specificName)).ToString(), parameters); - } - catch (Exception ex) - { - throw new MetadataException($"Error getting parameters for {schemaName}.{specificName}", ex); - } + throw new MetadataException($"Error getting parameters for {schemaName}.{specificName}", ex); } + } - private ScalarFunctionMetadata GetScalarFunctionInternal(MySqlObjectName tableFunctionName) - { - const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, DTD_IDENTIFIER, SPECIFIC_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA = @Schema AND ROUTINE_NAME = @Name;"; + private ScalarFunctionMetadata GetScalarFunctionInternal(MySqlObjectName tableFunctionName) + { + const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION, DTD_IDENTIFIER, SPECIFIC_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA = @Schema AND ROUTINE_NAME = @Name;"; - string actualSchema; - string actualName; + string actualSchema; + string actualName; - string fullTypeName; - string typeName; - UInt64? maxLength; - int? precision; - int? scale; - MySqlDbType? dbType; - string specificName; + string fullTypeName; + string typeName; + UInt64? maxLength; + int? precision; + int? scale; + MySqlDbType? dbType; + string specificName; - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(sql, con)) { - con.Open(); - using (var cmd = new MySqlCommand(sql, con)) + cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find scalar function {tableFunctionName}"); - actualSchema = reader.GetString("ROUTINE_SCHEMA"); - actualName = reader.GetString("ROUTINE_NAME"); - - typeName = reader.GetString("DATA_TYPE"); - maxLength = reader.GetUInt64OrNull("CHARACTER_MAXIMUM_LENGTH"); - var precisionA = reader.GetInt32OrNull("NUMERIC_PRECISION"); - scale = reader.GetInt32OrNull("NUMERIC_SCALE"); - var precisionB = reader.GetInt32OrNull("DATETIME_PRECISION"); - precision = precisionA ?? precisionB; - fullTypeName = reader.GetString("DTD_IDENTIFIER"); - specificName = reader.GetString("SPECIFIC_NAME"); - - var isUnsigned = fullTypeName.Contains("unsigned"); - dbType = SqlTypeNameToDbType(typeName, isUnsigned); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find scalar function {tableFunctionName}"); + actualSchema = reader.GetString("ROUTINE_SCHEMA"); + actualName = reader.GetString("ROUTINE_NAME"); + + typeName = reader.GetString("DATA_TYPE"); + maxLength = reader.GetUInt64OrNull("CHARACTER_MAXIMUM_LENGTH"); + var precisionA = reader.GetInt32OrNull("NUMERIC_PRECISION"); + scale = reader.GetInt32OrNull("NUMERIC_SCALE"); + var precisionB = reader.GetInt32OrNull("DATETIME_PRECISION"); + precision = precisionA ?? precisionB; + fullTypeName = reader.GetString("DTD_IDENTIFIER"); + specificName = reader.GetString("SPECIFIC_NAME"); + + var isUnsigned = fullTypeName.Contains("unsigned"); + dbType = SqlTypeNameToDbType(typeName, isUnsigned); } } + } - var objectName = new MySqlObjectName(actualSchema, actualName); + var objectName = new MySqlObjectName(actualSchema, actualName); - var parameters = GetParameters(actualSchema, specificName); + var parameters = GetParameters(actualSchema, specificName); - return new ScalarFunctionMetadata(objectName, parameters, typeName, dbType, true, (int?)maxLength, precision, scale, fullTypeName); - } + return new ScalarFunctionMetadata(objectName, parameters, typeName, dbType, true, (int?)maxLength, precision, scale, fullTypeName); + } - private StoredProcedureMetadata GetStoredProcedureInteral(MySqlObjectName storedProcedureName) - { - const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE' AND ROUTINE_SCHEMA = @Schema AND ROUTINE_NAME = @Name;"; + private StoredProcedureMetadata GetStoredProcedureInteral(MySqlObjectName storedProcedureName) + { + const string sql = "SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE' AND ROUTINE_SCHEMA = @Schema AND ROUTINE_NAME = @Name;"; - string actualSchema; - string actualName; + string actualSchema; + string actualName; - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(sql, con)) { - con.Open(); - using (var cmd = new MySqlCommand(sql, con)) + cmd.Parameters.AddWithValue("@Schema", storedProcedureName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", storedProcedureName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", storedProcedureName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", storedProcedureName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find stored procedure {storedProcedureName}"); - actualSchema = reader.GetString("ROUTINE_SCHEMA"); - actualName = reader.GetString("ROUTINE_NAME"); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find stored procedure {storedProcedureName}"); + actualSchema = reader.GetString("ROUTINE_SCHEMA"); + actualName = reader.GetString("ROUTINE_NAME"); } } + } - var objectName = new MySqlObjectName(actualSchema, actualName); + var objectName = new MySqlObjectName(actualSchema, actualName); - var parameters = GetParameters(actualSchema, actualName); + var parameters = GetParameters(actualSchema, actualName); - return new StoredProcedureMetadata(objectName, parameters); - } + return new StoredProcedureMetadata(objectName, parameters); + } - private TableOrViewMetadata GetTableOrViewInternal(MySqlObjectName tableName) - { - const string TableSql = @"SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, ENGINE FROM INFORMATION_SCHEMA.Tables WHERE TABLE_SCHEMA = @Schema AND TABLE_NAME = @Name"; + private TableOrViewMetadata GetTableOrViewInternal(MySqlObjectName tableName) + { + const string TableSql = @"SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, ENGINE FROM INFORMATION_SCHEMA.Tables WHERE TABLE_SCHEMA = @Schema AND TABLE_NAME = @Name"; - string actualSchemaName; - string actualTableName; - string? engine; - bool isTable; + string actualSchemaName; + string actualTableName; + string? engine; + bool isTable; - using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new MySqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new MySqlCommand(TableSql, con)) { - con.Open(); - using (var cmd = new MySqlCommand(TableSql, con)) + cmd.Parameters.AddWithValue("@Schema", tableName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", tableName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", tableName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find table or view {tableName}"); - actualSchemaName = reader.GetString("TABLE_SCHEMA"); - actualTableName = reader.GetString("TABLE_NAME"); - isTable = string.Equals(reader.GetString("TABLE_TYPE"), "BASE TABLE", StringComparison.Ordinal); - engine = reader.GetStringOrNull("ENGINE"); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find table or view {tableName}"); + actualSchemaName = reader.GetString("TABLE_SCHEMA"); + actualTableName = reader.GetString("TABLE_NAME"); + isTable = string.Equals(reader.GetString("TABLE_TYPE"), "BASE TABLE", StringComparison.Ordinal); + engine = reader.GetStringOrNull("ENGINE"); } } - - var columns = GetColumns(actualSchemaName, actualTableName); - - return new MySqlTableOrViewMetadata(this, new MySqlObjectName(actualSchemaName, actualTableName), isTable, columns, engine); } - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - /// https://stackoverflow.com/a/6582902/5274 - public override int? MaxParameters => 65535; + var columns = GetColumns(actualSchemaName, actualTableName); - class IndexTemp - { - public string? Collation { get; set; } - public string ColumnName { get; set; } = ""; - public string IndexName { get; set; } = ""; - public string IndexType { get; set; } = ""; - public bool NonUnique { get; set; } - public int Order { get; set; } - } + return new MySqlTableOrViewMetadata(this, new MySqlObjectName(actualSchemaName, actualTableName), isTable, columns, engine); + } + + class IndexTemp + { + public string? Collation { get; set; } + public string ColumnName { get; set; } = ""; + public string IndexName { get; set; } = ""; + public string IndexType { get; set; } = ""; + public bool NonUnique { get; set; } + public int Order { get; set; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlObjectName.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlObjectName.cs index 8e610cde5..0923adcd5 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlObjectName.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlObjectName.cs @@ -1,187 +1,186 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Represents an object in MySql (e.g. table, view, procedure) +/// +public struct MySqlObjectName : IEquatable { /// - /// Represents an object in MySql (e.g. table, view, procedure) + /// An empty schema/name pair + /// + public static readonly MySqlObjectName Empty; + + /// + /// Initializes a new instance of the struct. + /// + /// The schema. + /// The name. + public MySqlObjectName(string? schema, string name) + { + Schema = Normalize(schema); + Name = Normalize(name); + } + + /// + /// Initializes a new instance of the struct. /// - public struct MySqlObjectName : IEquatable + /// Name of the schema and. + public MySqlObjectName(string schemaAndName) { - /// - /// An empty schema/name pair - /// - public static readonly MySqlObjectName Empty; - - /// - /// Initializes a new instance of the struct. - /// - /// The schema. - /// The name. - public MySqlObjectName(string? schema, string name) + if (string.IsNullOrEmpty(schemaAndName)) + throw new ArgumentException($"{nameof(schemaAndName)} is null or empty.", nameof(schemaAndName)); + + var parts = schemaAndName.Split(new[] { '.' }, 2); + if (parts.Length == 1) { - Schema = Normalize(schema); - Name = Normalize(name); + Schema = null; + Name = Normalize(parts[0]); } - - /// - /// Initializes a new instance of the struct. - /// - /// Name of the schema and. - public MySqlObjectName(string schemaAndName) + else if (parts.Length == 2) { - if (string.IsNullOrEmpty(schemaAndName)) - throw new ArgumentException($"{nameof(schemaAndName)} is null or empty.", nameof(schemaAndName)); - - var parts = schemaAndName.Split(new[] { '.' }, 2); - if (parts.Length == 1) - { - Schema = null; - Name = Normalize(parts[0]); - } - else if (parts.Length == 2) - { - Schema = Normalize(parts[0]); - Name = Normalize(parts[1]); - } - else - { - throw new ArgumentException("Three-part identifiers are not supported."); - } + Schema = Normalize(parts[0]); + Name = Normalize(parts[1]); } + else + { + throw new ArgumentException("Three-part identifiers are not supported."); + } + } - /// - /// Gets the name. - /// - /// - /// The name. - /// - public string Name { get; } - - /// - /// Gets the schema. - /// - /// - /// The schema. - /// - public string? Schema { get; } + /// + /// Gets the name. + /// + /// + /// The name. + /// + public string Name { get; } + + /// + /// Gets the schema. + /// + /// + /// The schema. + /// + public string? Schema { get; } #pragma warning disable CA2225 // Operator overloads have named alternates - /// - /// Perform an implicit conversion from to . - /// - /// The value. - /// - /// The result of the conversion. - /// - public static implicit operator MySqlObjectName(string value) - { - return new MySqlObjectName(value); - } + /// + /// Perform an implicit conversion from to . + /// + /// The value. + /// + /// The result of the conversion. + /// + public static implicit operator MySqlObjectName(string value) + { + return new MySqlObjectName(value); + } #pragma warning restore CA2225 // Operator overloads have named alternates - /// - /// Implements the operator !=. - /// - /// The left value. - /// The right value. - /// - /// The result of the operator. - /// - /// This is a case-insensitive comparison. - public static bool operator !=(MySqlObjectName left, MySqlObjectName right) - { - return !(left == right); - } + /// + /// Implements the operator !=. + /// + /// The left value. + /// The right value. + /// + /// The result of the operator. + /// + /// This is a case-insensitive comparison. + public static bool operator !=(MySqlObjectName left, MySqlObjectName right) + { + return !(left == right); + } - /// - /// Implements the operator ==. - /// - /// The left value. - /// The right value. - /// - /// The result of the operator. - /// - /// This is a case-insensitive comparison. - public static bool operator ==(MySqlObjectName left, MySqlObjectName right) - { - return string.Equals(left.Schema, right.Schema, StringComparison.OrdinalIgnoreCase) - && string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); - } + /// + /// Implements the operator ==. + /// + /// The left value. + /// The right value. + /// + /// The result of the operator. + /// + /// This is a case-insensitive comparison. + public static bool operator ==(MySqlObjectName left, MySqlObjectName right) + { + return string.Equals(left.Schema, right.Schema, StringComparison.OrdinalIgnoreCase) + && string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); + } - /// - /// Determines whether the specified , is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - /// This is a case-insensitive comparison. - public override bool Equals(object? obj) - { - var other = obj as MySqlObjectName?; - if (other == null) - return false; - return this == other; - } + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + /// This is a case-insensitive comparison. + public override bool Equals(object? obj) + { + var other = obj as MySqlObjectName?; + if (other == null) + return false; + return this == other; + } - /// - /// Returns true if the two objects are equal. - /// - /// - /// - /// This is a case-insensitive comparison. - public bool Equals(MySqlObjectName other) - { - return this == other; - } + /// + /// Returns true if the two objects are equal. + /// + /// + /// + /// This is a case-insensitive comparison. + public bool Equals(MySqlObjectName other) + { + return this == other; + } - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - /// This is a case-insensitive comparison. - public override int GetHashCode() - { - return Name.ToUpperInvariant().GetHashCode(); - } + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + /// This is a case-insensitive comparison. + public override int GetHashCode() + { + return Name.ToUpperInvariant().GetHashCode(); + } - /// - /// To the quoted string. - /// - /// - public string ToQuotedString() - { - if (Schema == null) - return $"`{Name}`"; - else - return $"`{Schema}`.`{Name}`"; - } + /// + /// To the quoted string. + /// + /// + public string ToQuotedString() + { + if (Schema == null) + return $"`{Name}`"; + else + return $"`{Schema}`.`{Name}`"; + } - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - if (Schema == null) - return $"{Name}"; - return $"{Schema}.{Name}"; - } + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + if (Schema == null) + return $"{Name}"; + return $"{Schema}.{Name}"; + } - [return: NotNullIfNotNull("value")] - private static string? Normalize(string? value) - { - if (value.IsNullOrWhiteSpace()) - return null; + [return: NotNullIfNotNull("value")] + private static string? Normalize(string? value) + { + if (value.IsNullOrWhiteSpace()) + return null; - return value.Replace("`", ""); - } + return value.Replace("`", ""); } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlOpenDataSource.cs index 714cdbbb9..6e7251326 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlOpenDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlOpenDataSource.cs @@ -3,202 +3,201 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class SQLiteOpenDataSource. +/// +[UseTrait(typeof(Traits.OpenDataSourceTrait))] +public partial class MySqlOpenDataSource : MySqlDataSourceBase { + internal MySqlOpenDataSource(MySqlDataSource dataSource, MySqlConnection connection, MySqlTransaction? transaction) : base(new MySqlDataSourceSettings(dataSource) + ) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + + m_BaseDataSource = dataSource; + m_Connection = connection; + m_Transaction = transaction; + } + /// - /// Class SQLiteOpenDataSource. + /// Executes the specified operation. /// - [UseTrait(typeof(Traits.OpenDataSourceTrait))] - public partial class MySqlOpenDataSource : MySqlDataSourceBase + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) { - internal MySqlOpenDataSource(MySqlDataSource dataSource, MySqlConnection connection, MySqlTransaction? transaction) : base(new MySqlDataSourceSettings(dataSource) - ) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - m_BaseDataSource = dataSource; - m_Connection = connection; - m_Transaction = transaction; - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try - { - using (var cmd = new MySqlCommand()) - { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = implementation(cmd); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) + using (var cmd = new MySqlCommand()) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + + var rows = implementation(cmd); + + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected async override Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var cmd = new MySqlCommand()) { - var rows = implementation(m_Connection, m_Transaction); + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + + var rows = await implementation(cmd).ConfigureAwait(false); + + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } } - - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected async override Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var cmd = new MySqlCommand()) - { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = await implementation(cmd).ConfigureAwait(false); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - private partial MySqlOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) - { - if (userValue != null) - UserValue = userValue; - if (additionalRules != null) - AuditRules = new AuditRuleCollection(AuditRules, additionalRules); + private partial MySqlOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) + { + if (userValue != null) + UserValue = userValue; + if (additionalRules != null) + AuditRules = new AuditRuleCollection(AuditRules, additionalRules); - return this; - } + return this; } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTableOrViewMetadata`1.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTableOrViewMetadata`1.cs index be250d6e9..012352604 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTableOrViewMetadata`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTableOrViewMetadata`1.cs @@ -1,33 +1,32 @@ using MySqlConnector; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class MySqlTableOrViewMetadata. +/// +/// +public class MySqlTableOrViewMetadata : TableOrViewMetadata { /// - /// Class MySqlTableOrViewMetadata. + /// Initializes a new instance of the class. /// - /// - public class MySqlTableOrViewMetadata : TableOrViewMetadata + /// The metadata cache. + /// The name. + /// if set to true is a table. + /// The columns. + /// The engine. + internal MySqlTableOrViewMetadata(DatabaseMetadataCache metadataCache, MySqlObjectName name, bool isTable, ColumnMetadataCollection columns, string? engine) : base(metadataCache, name, isTable, columns) { - /// - /// Initializes a new instance of the class. - /// - /// The metadata cache. - /// The name. - /// if set to true is a table. - /// The columns. - /// The engine. - internal MySqlTableOrViewMetadata(DatabaseMetadataCache metadataCache, MySqlObjectName name, bool isTable, ColumnMetadataCollection columns, string? engine) : base(metadataCache, name, isTable, columns) - { - Engine = engine; - } - - /// - /// Gets the engine. - /// - /// - /// The engine. - /// - public string? Engine { get; } + Engine = engine; } -} + + /// + /// Gets the engine. + /// + /// + /// The engine. + /// + public string? Engine { get; } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTransactionalDataSource.cs index eb75dbd4b..c47aaa56a 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTransactionalDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/MySqlTransactionalDataSource.cs @@ -2,264 +2,261 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +/// +/// Class MySqlTransactionalDataSource +/// +/// +/// +[UseTrait(typeof(Traits.TransactionalDataSourceTrait))] +public partial class MySqlTransactionalDataSource : MySqlDataSourceBase { /// - /// Class MySqlTransactionalDataSource + /// Initializes a new instance of the class. /// - /// - /// - [UseTrait(typeof(Traits.TransactionalDataSourceTrait))] - public partial class MySqlTransactionalDataSource : MySqlDataSourceBase + /// The data source. + /// The isolation level. + /// if set to true [forward events]. + public MySqlTransactionalDataSource(MySqlDataSource dataSource, IsolationLevel? isolationLevel, bool forwardEvents) + : base(new MySqlDataSourceSettings(dataSource, forwardEvents)) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The isolation level. - /// if set to true [forward events]. - public MySqlTransactionalDataSource(MySqlDataSource dataSource, IsolationLevel? isolationLevel, bool forwardEvents) - : base(new MySqlDataSourceSettings(dataSource, forwardEvents)) - { - Name = dataSource.Name; + Name = dataSource.Name; - m_BaseDataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - m_Connection = dataSource.CreateConnection(); + m_BaseDataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + m_Connection = dataSource.CreateConnection(); - if (isolationLevel == null) - m_Transaction = m_Connection.BeginTransaction(); - else - m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value); + if (isolationLevel == null) + m_Transaction = m_Connection.BeginTransaction(); + else + m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value); - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// if set to true [forward events]. - /// The connection. - /// The transaction. - internal MySqlTransactionalDataSource(MySqlDataSource dataSource, bool forwardEvents, MySqlConnection connection, MySqlTransaction transaction) - : base(new MySqlDataSourceSettings(dataSource, forwardEvents)) - { - Name = dataSource.Name; + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// if set to true [forward events]. + /// The connection. + /// The transaction. + internal MySqlTransactionalDataSource(MySqlDataSource dataSource, bool forwardEvents, MySqlConnection connection, MySqlTransaction transaction) + : base(new MySqlDataSourceSettings(dataSource, forwardEvents)) + { + Name = dataSource.Name; - m_BaseDataSource = dataSource; - m_Connection = connection; - m_Transaction = transaction; + m_BaseDataSource = dataSource; + m_Connection = connection; + m_Transaction = transaction; - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + using (var cmd = new MySqlCommand()) { - using (var cmd = new MySqlCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); - var rows = implementation(cmd); + var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// + /// Task. + /// + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var cmd = new MySqlCommand()) { - var rows = implementation(m_Connection, m_Transaction); + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + + var rows = await implementation(cmd).ConfigureAwait(false); + + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } } - - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// - /// Task. - /// - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var cmd = new MySqlCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = await implementation(cmd).ConfigureAwait(false); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// - /// Task. - /// - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// + /// Task. + /// + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/Utilities.cs index 26b05dc8b..d92bbf8aa 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySql/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySql/Utilities.cs @@ -1,39 +1,49 @@ using MySqlConnector; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.MySql +namespace Tortuga.Chain.MySql; + +internal static class Utilities { - internal static class Utilities + /// + /// Gets the parameters from a SQL Builder. + /// + /// The SQL builder. + /// + public static List GetParameters(this SqlBuilder sqlBuilder) { - /// - /// Gets the parameters from a SQL Builder. - /// - /// The SQL builder. - /// - public static List GetParameters(this SqlBuilder sqlBuilder) - { - return sqlBuilder.GetParameters(ParameterBuilderCallback); - } + return sqlBuilder.GetParameters(ParameterBuilderCallback); + } - public static MySqlParameter ParameterBuilderCallback(SqlBuilderEntry entry) + public static MySqlParameter ParameterBuilderCallback(SqlBuilderEntry entry) + { + var result = new MySqlParameter(); + result.ParameterName = entry.Details.SqlVariableName; + result.Value = entry.ParameterValue; + if (entry.Details.DbType.HasValue) + result.MySqlDbType = entry.Details.DbType.Value; + return result; + } + + public static bool PrimaryKeyIsIdentity(this SqlBuilder sqlBuilder, out List keyParameters) + { + return sqlBuilder.PrimaryKeyIsIdentity((MySqlDbType? type) => { var result = new MySqlParameter(); - result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; - if (entry.Details.DbType.HasValue) - result.MySqlDbType = entry.Details.DbType.Value; + if (type.HasValue) + result.MySqlDbType = type.Value; return result; - } + }, out keyParameters); + } - public static bool PrimaryKeyIsIdentity(this SqlBuilder sqlBuilder, out List keyParameters) + public static bool RequiresSorting(this MySqlLimitOption limitOption) + { + return limitOption switch { - return sqlBuilder.PrimaryKeyIsIdentity((MySqlDbType? type) => - { - var result = new MySqlParameter(); - if (type.HasValue) - result.MySqlDbType = type.Value; - return result; - }, out keyParameters); - } + MySqlLimitOption.None => false, + MySqlLimitOption.Rows => true, + MySqlLimitOption.RandomSampleRows => false, + _ => throw new ArgumentOutOfRangeException(nameof(limitOption), limitOption, "Unknown limit option") + }; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySqlDataSource.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySqlDataSource.cs index c339bff93..2a1f9bc45 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySqlDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySqlDataSource.cs @@ -3,340 +3,323 @@ using Tortuga.Chain.Core; using Tortuga.Chain.MySql; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class MySqlDataSource. +/// +/// +public partial class MySqlDataSource : MySqlDataSourceBase { + MySqlMetadataCache m_DatabaseMetadata; + /// - /// Class MySqlDataSource. + /// Initializes a new instance of the class. /// - /// - public partial class MySqlDataSource : MySqlDataSourceBase + /// The name. + /// The connection string. + /// The settings. + /// connectionString is null or empty.;connectionString + public MySqlDataSource(string? name, string connectionString, MySqlDataSourceSettings? settings = null) + : base(settings) { - MySqlMetadataCache m_DatabaseMetadata; - - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The connection string. - /// The settings. - /// connectionString is null or empty.;connectionString - public MySqlDataSource(string? name, string connectionString, MySqlDataSourceSettings? settings = null) - : base(settings) - { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); - m_ConnectionBuilder = new MySqlConnectionStringBuilder(connectionString); + m_ConnectionBuilder = new MySqlConnectionStringBuilder(connectionString); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.Database; - else - Name = name; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.Database; + else + Name = name; - m_DatabaseMetadata = new MySqlMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + m_DatabaseMetadata = new MySqlMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - /// - /// Initializes a new instance of the class. - /// - /// The connection string. - /// The settings. - public MySqlDataSource(string connectionString, MySqlDataSourceSettings? settings = null) - : this(null, connectionString, settings) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The connection string. + /// The settings. + public MySqlDataSource(string connectionString, MySqlDataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The connection builder. - /// The settings. - /// - public MySqlDataSource(string? name, MySqlConnectionStringBuilder connectionBuilder, MySqlDataSourceSettings? settings = null) - : base(settings) - { - if (connectionBuilder == null) - throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The connection builder. + /// The settings. + /// + public MySqlDataSource(string? name, MySqlConnectionStringBuilder connectionBuilder, MySqlDataSourceSettings? settings = null) + : base(settings) + { + if (connectionBuilder == null) + throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); + + m_ConnectionBuilder = connectionBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.Database; + else + Name = name; + + m_DatabaseMetadata = new MySqlMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - m_ConnectionBuilder = connectionBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.Database; - else - Name = name; + /// + /// Initializes a new instance of the class. + /// + /// The connection builder. + /// The settings. + public MySqlDataSource(MySqlConnectionStringBuilder connectionBuilder, MySqlDataSourceSettings? settings = null) + : this(null, connectionBuilder, settings) + { + } - m_DatabaseMetadata = new MySqlMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + MySqlDataSource(string? name, MySqlConnectionStringBuilder connectionBuilder, MySqlDataSourceSettings settings, MySqlMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) + : base(settings) + { + if (connectionBuilder == null) + throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); + + m_ConnectionBuilder = connectionBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.Database; + else + Name = name; + + m_DatabaseMetadata = databaseMetadata; + m_ExtensionCache = extensionCache; + m_Cache = cache; + } - /// - /// Initializes a new instance of the class. - /// - /// The connection builder. - /// The settings. - public MySqlDataSource(MySqlConnectionStringBuilder connectionBuilder, MySqlDataSourceSettings? settings = null) - : this(null, connectionBuilder, settings) - { - } + /// + /// Gets the database metadata. + /// + /// The database metadata. + public override MySqlMetadataCache DatabaseMetadata + { + get { return m_DatabaseMetadata; } + } - MySqlDataSource(string? name, MySqlConnectionStringBuilder connectionBuilder, MySqlDataSourceSettings settings, MySqlMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) - : base(settings) + /// + /// Creates a new data source with the indicated changes to the settings. + /// + /// The new settings to use. + /// + /// The new data source will share the same database metadata cache. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public MySqlDataSource WithSettings(MySqlDataSourceSettings? settings) + { + var mergedSettings = new MySqlDataSourceSettings() { - if (connectionBuilder == null) - throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); + DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, + SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, + StrictMode = settings?.StrictMode ?? StrictMode, + SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode + }; + var result = new MySqlDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); + result.m_DatabaseMetadata = m_DatabaseMetadata; + result.AuditRules = AuditRules; + result.UserValue = UserValue; + + result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); + result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); + result.ExecutionError += (sender, e) => OnExecutionError(e); + result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); + + return result; + } - m_ConnectionBuilder = connectionBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.Database; - else - Name = name; + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// System.Nullable<System.Int32>. + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - m_DatabaseMetadata = databaseMetadata; - m_ExtensionCache = extensionCache; - m_Cache = cache; - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Gets the database metadata. - /// - /// The database metadata. - public override MySqlMetadataCache DatabaseMetadata + try { - get { return m_DatabaseMetadata; } - } - + using (var con = CreateConnection()) + { + using (var cmd = new MySqlCommand()) + { + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + var rows = implementation(cmd); - /// - /// Creates a new data source with the indicated changes to the settings. - /// - /// The new settings to use. - /// - /// The new data source will share the same database metadata cache. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] - public MySqlDataSource WithSettings(MySqlDataSourceSettings? settings) + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + } + } + catch (Exception ex) { - var mergedSettings = new MySqlDataSourceSettings() - { - DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, - SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, - StrictMode = settings?.StrictMode ?? StrictMode, - SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode - }; - var result = new MySqlDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); - result.m_DatabaseMetadata = m_DatabaseMetadata; - result.AuditRules = AuditRules; - result.UserValue = UserValue; - - result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); - result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); - result.ExecutionError += (sender, e) => OnExecutionError(e); - result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); - - return result; + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// System.Nullable<System.Int32>. - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var con = CreateConnection()) { - using (var con = CreateConnection()) - { - using (var cmd = new MySqlCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = implementation(cmd); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - using (var con = CreateConnection()) + using (var cmd = new MySqlCommand()) { - var rows = implementation(con, null); + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + var rows = await implementation(cmd).ConfigureAwait(false); + + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } } - catch (Exception ex) + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException + { + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; + } + else { OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); throw; } } + } - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try - { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - using (var cmd = new MySqlCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = await implementation(cmd).ConfigureAwait(false); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) + try + { + using (var con = CreateConnection()) { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = CreateConnection()) - { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySqlExtensions.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySqlExtensions.cs index 6b88872c2..65029c551 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySqlExtensions.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySqlExtensions.cs @@ -2,48 +2,47 @@ using System.Collections.Concurrent; using Tortuga.Chain.MySql; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class SqlServerExtensions. +/// +public static class MySqlExtensions { + readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + /// - /// Class SqlServerExtensions. + /// Returns a data source wrapped around the connection. /// - public static class MySqlExtensions + /// The connection. + /// SqlServerOpenDataSource. + /// + public static MySqlOpenDataSource AsDataSource(this MySqlConnection connection) { - readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - /// - /// Returns a data source wrapped around the connection. - /// - /// The connection. - /// SqlServerOpenDataSource. - /// - public static MySqlOpenDataSource AsDataSource(this MySqlConnection connection) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); - - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new MySqlDataSource(cs)); - return new MySqlOpenDataSource(dataSourceBase, connection, null); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new MySqlDataSource(cs)); + return new MySqlOpenDataSource(dataSourceBase, connection, null); + } - /// - /// Returns a data source wrapped around the transaction. - /// - /// The connection. - /// The transaction. - /// SqlServerOpenDataSource. - /// - public static MySqlOpenDataSource AsDataSource(this MySqlConnection connection, MySqlTransaction transaction) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); + /// + /// Returns a data source wrapped around the transaction. + /// + /// The connection. + /// The transaction. + /// SqlServerOpenDataSource. + /// + public static MySqlOpenDataSource AsDataSource(this MySqlConnection connection, MySqlTransaction transaction) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new MySqlDataSource(cs)); - return new MySqlOpenDataSource(dataSourceBase, connection, transaction); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new MySqlDataSource(cs)); + return new MySqlOpenDataSource(dataSourceBase, connection, transaction); } } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/MySqlLimitOption.cs b/Tortuga.Chain/Tortuga.Chain.MySql/MySqlLimitOption.cs index 002a14c21..230c869d6 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/MySqlLimitOption.cs +++ b/Tortuga.Chain/Tortuga.Chain.MySql/MySqlLimitOption.cs @@ -1,26 +1,24 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Limit options supported by PostgreSQL. +/// +/// This is a strict subset of LimitOptions +public enum MySqlLimitOption { /// - /// Limit options supported by PostgreSQL. + /// No limits were applied. /// - /// This is a strict subset of LimitOptions - public enum MySqlLimitOption - { - /// - /// No limits were applied. - /// - None = LimitOptions.None, - - /// - /// Returns the indicated number of rows with optional offset - /// - Rows = LimitOptions.Rows, + None = LimitOptions.None, - /// - /// Randomly sample the indicated number of rows - /// - /// WARNING: This uses "ORDER BY RAND()", which is inappropriate for large tables. - RandomSampleRows = LimitOptions.RandomSampleRows, + /// + /// Returns the indicated number of rows with optional offset + /// + Rows = LimitOptions.Rows, - } + /// + /// Randomly sample the indicated number of rows + /// + /// WARNING: This uses "ORDER BY RAND()", which is inappropriate for large tables. + RandomSampleRows = LimitOptions.RandomSampleRows, } diff --git a/Tortuga.Chain/Tortuga.Chain.MySql/Tortuga.Chain.MySql.csproj b/Tortuga.Chain/Tortuga.Chain.MySql/Tortuga.Chain.MySql.csproj index 6e6d1abaf..bc071c035 100644 --- a/Tortuga.Chain/Tortuga.Chain.MySql/Tortuga.Chain.MySql.csproj +++ b/Tortuga.Chain/Tortuga.Chain.MySql/Tortuga.Chain.MySql.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -57,7 +57,7 @@ - + @@ -77,7 +77,7 @@ - true + Generated @@ -85,7 +85,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql.Tests/Setup.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql.Tests/Setup.cs index 59abc10f3..dbb100390 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql.Tests/Setup.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql.Tests/Setup.cs @@ -96,7 +96,9 @@ State CHAR(2) NOT NULL, DeletedFlag boolean NOT NULL DEFAULT FALSE, DeletedDate TIMESTAMP NULL, - DeletedByKey INTEGER NULL + DeletedByKey INTEGER NULL, + BirthDay DATE NULL, + PreferredCallTime TIME NULL )"; string sql4 = @" diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index 0fab2b839..000000000 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* -Container class: Tortuga.Chain.PostgreSqlDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.PostgreSql.PostgreSqlDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsTruncateTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsInsertBatchTrait> - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait - Adding trait: Traits.SupportsUpsertTrait - Adding trait: Traits.SupportsInsertBulkTrait - Adding trait: Traits.SupportsScalarFunctionTrait - Adding trait: Traits.SupportsProcedureTrait - Adding trait: Traits.SupportsTableFunctionTrait -Container class: Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlDataSourceBase.cs deleted file mode 100644 index dabb6cdb4..000000000 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlDataSourceBase.cs +++ /dev/null @@ -1,1408 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.PostgreSql -{ - partial class PostgreSqlDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsTruncate, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsInsertBatch, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Tortuga.Chain.DataSources.ISupportsUpsert, Tortuga.Chain.DataSources.ISupportsInsertBulk, Tortuga.Chain.DataSources.ISupportsScalarFunction, Tortuga.Chain.DataSources.ISupportsProcedure, Tortuga.Chain.DataSources.ISupportsTableFunction, Traits.ICommandHelper, Traits.IInsertBatchHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper, Traits.IUpsertHelper, Traits.IInsertBulkHelper, Traits.ICommandHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsTruncateTrait ___Trait1 = new(); - private Traits.SupportsTruncateTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait2 = new(); - private Traits.SupportsSqlQueriesTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsInsertBatchTrait> ___Trait3 = new(); - private Traits.SupportsInsertBatchTrait> __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait4 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsUpdateTrait ___Trait5 = new(); - private Traits.SupportsUpdateTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsDeleteTrait ___Trait6 = new(); - private Traits.SupportsDeleteTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait7 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsInsertTrait ___Trait8 = new(); - private Traits.SupportsInsertTrait __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsUpdateSet ___Trait9 = new(); - private Traits.SupportsUpdateSet __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsDeleteSet ___Trait10 = new(); - private Traits.SupportsDeleteSet __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - private Traits.SupportsFromTrait ___Trait11 = new(); - private Traits.SupportsFromTrait __Trait11 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait11; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait12 = new(); - private Traits.SupportsGetByKeyListTrait __Trait12 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait12; - } - } - private Traits.SupportsUpsertTrait ___Trait13 = new(); - private Traits.SupportsUpsertTrait __Trait13 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait13; - } - } - private Traits.SupportsInsertBulkTrait ___Trait14 = new(); - private Traits.SupportsInsertBulkTrait __Trait14 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait14; - } - } - private Traits.SupportsScalarFunctionTrait ___Trait15 = new(); - private Traits.SupportsScalarFunctionTrait __Trait15 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait15; - } - } - private Traits.SupportsProcedureTrait ___Trait16 = new(); - private Traits.SupportsProcedureTrait __Trait16 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait16; - } - } - private Traits.SupportsTableFunctionTrait ___Trait17 = new(); - private Traits.SupportsTableFunctionTrait __Trait17 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait17; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait6).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait6).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait4).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBatch - Tortuga.Chain.CommandBuilders.IDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertBatch(objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.String tableName, System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(tableName, objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(objects, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBulk - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, objects); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(objects); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsProcedure - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName); - } - - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsScalarFunction - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName); - } - - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait2).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTableFunction - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait17).TableFunction(functionName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait17).TableFunction(functionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTruncate - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate() - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait7).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, newValues, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(argumentValue, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait10.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait10.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait10.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait10.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait6.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait6.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableOrViewName) - { - return __Trait11.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableOrViewName, System.String whereClause) - { - return __Trait11.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait11.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait11.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait11.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait11.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait11.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait11.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.String key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TKey key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertBatchTrait> - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// Name of the table. - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder InsertBatch(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(objects, options); - } - - /// - /// Performs a series of batch inserts. - /// - /// The type of the t object. - /// Name of the table. - /// The objects. - /// The options. - /// Tortuga.Chain.ILink<System.Int32>. - /// This operation is not atomic. It should be wrapped in a transaction. - public Tortuga.Chain.ILink InsertMultipleBatch(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.ILink InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(objects, options); - } - - // Exposing trait Traits.SupportsInsertBulkTrait - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data table. - /// TInsertBulkCommand. - public Tortuga.Chain.PostgreSql.CommandBuilders.PostgreSqlInsertBulk InsertBulk(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Data.DataTable dataTable) - { - return __Trait14.InsertBulk(tableName, dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data reader. - /// TInsertBulkCommand. - public Tortuga.Chain.PostgreSql.CommandBuilders.PostgreSqlInsertBulk InsertBulk(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Data.IDataReader dataReader) - { - return __Trait14.InsertBulk(tableName, dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// - /// Name of the table. - /// The objects. - /// TInsertBulkCommand. - public Tortuga.Chain.PostgreSql.CommandBuilders.PostgreSqlInsertBulk InsertBulk(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(tableName, objects); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data table. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.PostgreSql.CommandBuilders.PostgreSqlInsertBulk InsertBulk(System.Data.DataTable dataTable)where TObject : class - { - return __Trait14.InsertBulk(dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data reader. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.PostgreSql.CommandBuilders.PostgreSqlInsertBulk InsertBulk(System.Data.IDataReader dataReader)where TObject : class - { - return __Trait14.InsertBulk(dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The objects. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.PostgreSql.CommandBuilders.PostgreSqlInsertBulk InsertBulk(System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(objects); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsProcedureTrait - - /// - /// Loads a procedure definition - /// - /// Name of the procedure. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.PostgreSql.PostgreSqlObjectName procedureName) - { - return __Trait16.Procedure(procedureName); - } - - /// - /// Loads a procedure definition and populates it using the parameter object. - /// - /// Name of the procedure. - /// The argument value. - /// - /// - /// The procedure's definition is loaded from the database and used to determine which properties on the parameter object to use. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.PostgreSql.PostgreSqlObjectName procedureName, System.Object argumentValue) - { - return __Trait16.Procedure(procedureName, argumentValue); - } - - // Exposing trait Traits.SupportsScalarFunctionTrait - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.PostgreSql.PostgreSqlObjectName scalarFunctionName) - { - return __Trait15.ScalarFunction(scalarFunctionName); - } - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.PostgreSql.PostgreSqlObjectName scalarFunctionName, System.Object functionArgumentValue) - { - return __Trait15.ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait2.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait2.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsTableFunctionTrait - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableFunctionName) - { - return __Trait17.TableFunction(tableFunctionName); - } - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableFunctionName, System.Object functionArgumentValue) - { - return __Trait17.TableFunction(tableFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsTruncateTrait - - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName) - { - return __Trait1.Truncate(tableName); - } - - /// Truncates the specified table. - /// This class used to determine which table to Truncate - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate()where TObject : class - { - return __Trait1.Truncate(); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsUpsertTrait - - /// - /// Creates a operation used to perform an "upsert" operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(tableName, argumentValue, options); - } - - /// - /// Perform an insert or update operation as appropriate. - /// - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder OnProcedure(Tortuga.Chain.PostgreSql.PostgreSqlObjectName procedureName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder OnScalarFunction(Tortuga.Chain.PostgreSql.PostgreSqlObjectName scalarFunctionName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.TableDbCommandBuilder OnTableFunction(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableFunctionName, System.Object? functionArgumentValue ); - - private partial Tortuga.Chain.ILink OnTruncate(Tortuga.Chain.PostgreSql.PostgreSqlObjectName tableName ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.OnTruncate = OnTruncate; - __Trait1.DataSource = this; - __Trait2.OnSql = OnSql; - __Trait3.DataSource = this; - __Trait4.DataSource = this; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - __Trait11.DataSource = this; - __Trait12.DataSource = this; - __Trait13.DataSource = this; - __Trait14.DataSource = this; - __Trait15.OnScalarFunction = OnScalarFunction; - __Trait15.DataSource = this; - __Trait16.OnProcedure = OnProcedure; - __Trait16.DataSource = this; - __Trait17.OnTableFunction = OnTableFunction; - __Trait17.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource.cs deleted file mode 100644 index 388f3ca64..000000000 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.PostgreSql -{ - partial class PostgreSqlOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public Npgsql.NpgsqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public Npgsql.NpgsqlTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.PostgreSql.PostgreSqlMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.PostgreSqlDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private Npgsql.NpgsqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private Npgsql.NpgsqlTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource.cs deleted file mode 100644 index 652a60117..000000000 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.PostgreSql -{ - partial class PostgreSqlTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public Npgsql.NpgsqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public Npgsql.NpgsqlTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.PostgreSql.PostgreSqlMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.PostgreSqlDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private Npgsql.NpgsqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private Npgsql.NpgsqlTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSqlDataSource.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSqlDataSource.cs deleted file mode 100644 index 797c77934..000000000 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.PostgreSqlDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class PostgreSqlDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public Npgsql.NpgsqlConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource CreateOpenDataSource(Npgsql.NpgsqlConnection connection, Npgsql.NpgsqlTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private Npgsql.NpgsqlConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.PostgreSqlDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.PostgreSqlDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.PostgreSqlDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.PostgreSqlDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.PostgreSql.PostgreSqlTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.PostgreSqlDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial Npgsql.NpgsqlConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.PostgreSql.PostgreSqlOpenDataSource OnCreateOpenDataSource(Npgsql.NpgsqlConnection connection, Npgsql.NpgsqlTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlDeleteSet.cs index 4a40d3f87..e511f4b00 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlDeleteSet.cs @@ -14,13 +14,13 @@ namespace Tortuga.Chain.PostgreSql.CommandBuilders internal sealed class PostgreSqlDeleteSet : MultipleRowDbCommandBuilder { readonly object? m_ArgumentValue; + readonly int? m_ExpectedRowCount; readonly FilterOptions m_FilterOptions; readonly object? m_FilterValue; + readonly DeleteOptions m_Options; readonly IEnumerable? m_Parameters; readonly TableOrViewMetadata m_Table; readonly string? m_WhereClause; - readonly DeleteOptions m_Options; - readonly int? m_ExpectedRowCount; /// /// Initializes a new instance of the class. @@ -129,4 +129,4 @@ public override CommandExecutionToken Prepare(Ma /// public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBatch`1.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBatch`1.cs index 5e5fe7c7a..5d19d8ed6 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBatch`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBatch`1.cs @@ -105,4 +105,4 @@ public override CommandExecutionToken Prepare(Ma /// public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBulk.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBulk.cs index b80fd7c46..9fa69fb75 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBulk.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlInsertBulk.cs @@ -45,22 +45,6 @@ internal PostgreSqlInsertBulk(PostgreSqlDataSourceBase dataSource, PostgreSqlObj throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); } - /// - /// After notifyAfter records, the event handler may be fired. This can be used to abort the bulk insert. - /// - /// The event handler. - /// The notify after. This should be a multiple of the batch size. - public PostgreSqlInsertBulk WithNotifications(EventHandler eventHandler, int notifyAfter) - { - if (eventHandler == null) - throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); - if (notifyAfter <= 0) - throw new ArgumentException($"{nameof(notifyAfter)} must be greater than 0.", nameof(notifyAfter)); - m_EventHandler = eventHandler; - m_NotifyAfter = notifyAfter; - return this; - } - /// /// Prepares the command for execution by generating any necessary SQL. /// @@ -91,6 +75,22 @@ public override OperationExecutionToken Pre /// public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + /// + /// After notifyAfter records, the event handler may be fired. This can be used to abort the bulk insert. + /// + /// The event handler. + /// The notify after. This should be a multiple of the batch size. + public PostgreSqlInsertBulk WithNotifications(EventHandler eventHandler, int notifyAfter) + { + if (eventHandler == null) + throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); + if (notifyAfter <= 0) + throw new ArgumentException($"{nameof(notifyAfter)} must be greater than 0.", nameof(notifyAfter)); + m_EventHandler = eventHandler; + m_NotifyAfter = notifyAfter; + return this; + } + /// /// Implementation the specified operation. /// @@ -194,12 +194,6 @@ public override OperationExecutionToken Pre return rowCount; } - string SetupSql(List<(int ColumnIndex, ColumnMetadata Column)> columns) - { - var columnList = string.Join(",", columns.Select(c => c.Column.QuotedSqlName)); - return $"copy {m_Table.Name.ToQuotedString() }({columnList}) from STDIN (FORMAT BINARY)"; - } - List<(int ColumnIndex, ColumnMetadata Column)> SetupColumns() { var mappedColumns = new List<(int ColumnIndex, ColumnMetadata Column)>(m_Source.FieldCount); @@ -223,5 +217,11 @@ string SetupSql(List<(int ColumnIndex, ColumnMetadata Column)> col return mappedColumns; } + + string SetupSql(List<(int ColumnIndex, ColumnMetadata Column)> columns) + { + var columnList = string.Join(",", columns.Select(c => c.Column.QuotedSqlName)); + return $"copy {m_Table.Name.ToQuotedString()}({columnList}) from STDIN (FORMAT BINARY)"; + } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlObjectCommand.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlObjectCommand.cs index 3ee9d77ea..450346a82 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlObjectCommand.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlObjectCommand.cs @@ -34,4 +34,4 @@ protected PostgreSqlObjectCommand(PostgreSqlDataSourceBase dataSource, PostgreSq /// protected override TableOrViewMetadata OnGetTable() => Table; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableFunction.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableFunction.cs index 36494d158..d01048366 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableFunction.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableFunction.cs @@ -145,6 +145,10 @@ public override CommandExecutionToken Prepare(Ma sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); parameters = sqlBuilder.GetParameters(); } + + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any() && StrictMode) + throw new InvalidOperationException("Limits were requested without a sort order. Use WithSorting to supply a sort order or disable strict mode."); + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); switch (m_LimitOptions) @@ -218,21 +222,6 @@ protected override TableDbCommandBuilder - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); - - m_SortExpressions = sortExpressions; - return this; - } - /// /// Adds limits to the command builder. /// @@ -264,5 +253,20 @@ protected override TableDbCommandBuilder + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; + } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableOrView.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableOrView.cs index 183acfa4f..df9df2fe8 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableOrView.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlTableOrView.cs @@ -197,7 +197,18 @@ public override CommandExecutionToken Prepare(Ma sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); parameters = sqlBuilder.GetParameters(); } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any()) + { + if (m_Table.HasPrimaryKey) + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_Table.PrimaryKeyColumns.Select(x => new SortExpression(x.SqlName)), null); + else if (StrictMode) + throw new InvalidOperationException("Limits were requested, but no primary keys were detected. Use WithSorting to supply a sort order or disable strict mode."); + } + else + { + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + } switch (m_LimitOptions) { @@ -270,17 +281,6 @@ protected override TableDbCommandBuilder - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - m_SortExpressions = sortExpressions ?? throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); - return this; - } - /// /// Adds limits to the command builder. /// @@ -314,5 +314,16 @@ protected override TableDbCommandBuilder + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + m_SortExpressions = sortExpressions ?? throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + return this; + } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlUpdateSet.cs index 2a3c64204..067db071a 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/CommandBuilders/PostgreSqlUpdateSet.cs @@ -234,4 +234,4 @@ public override UpdateSetDbCommandBuilder WithFi return this; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlDataSourceBase.Traits.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlDataSourceBase.Traits.cs index d20ebeed8..79d38a2da 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlDataSourceBase.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlDataSourceBase.Traits.cs @@ -9,8 +9,8 @@ namespace Tortuga.Chain.PostgreSql; -[UseTrait(typeof(SupportsDeleteAllTrait))] -[UseTrait(typeof(SupportsTruncateTrait))] +[UseTrait(typeof(SupportsDeleteAllTrait))] +[UseTrait(typeof(SupportsTruncateTrait))] [UseTrait(typeof(SupportsSqlQueriesTrait))] [UseTrait(typeof(SupportsInsertBatchTrait>))] @@ -28,9 +28,9 @@ namespace Tortuga.Chain.PostgreSql; [UseTrait(typeof(SupportsScalarFunctionTrait))] [UseTrait(typeof(SupportsProcedureTrait))] [UseTrait(typeof(SupportsTableFunctionTrait))] +[UseTrait(typeof(SupportsGetByColumnListTrait))] partial class PostgreSqlDataSourceBase : ICrudDataSource, IAdvancedCrudDataSource { - DatabaseMetadataCache ICommandHelper.DatabaseMetadata => DatabaseMetadata; List ICommandHelper.GetParameters(SqlBuilder builder) => builder.GetParameters(); @@ -101,7 +101,7 @@ TableDbCommandBuilder(this, tableOrViewName, filterValue, filterOptions); } - SingleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class { string where = keyColumn.SqlName + " = @Param0"; @@ -113,7 +113,6 @@ SingleRowDbCommandBuilder IGetByKeyHelper(this, tableName, where, parameters); - } MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKeyList(AbstractObjectName tableName, ColumnMetadata keyColumn, IEnumerable keys) where TObject : class @@ -135,7 +134,6 @@ MultipleRowDbCommandBuilder IGetByKeyHelper< } return new MultipleRowDbCommandBuilder(new PostgreSqlTableOrView(this, tableName, where, parameters)); - } DbCommandBuilder IInsertBatchHelper.OnInsertBatch(AbstractObjectName tableName, IEnumerable objects, InsertOptions options) @@ -143,12 +141,27 @@ DbCommandBuilder IInsertBatchHelper(this, tableName, objects, options); ; } + PostgreSqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, DataTable dataTable) + { + return new PostgreSqlInsertBulk(this, tableName, dataTable); + } + + PostgreSqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, IDataReader dataReader) + { + return new PostgreSqlInsertBulk(this, tableName, dataReader); + } + ObjectDbCommandBuilder IInsertHelper.OnInsertObject(AbstractObjectName tableName, TArgument argumentValue, InsertOptions options) -where TArgument : class + where TArgument : class { return new PostgreSqlInsertObject(this, tableName, argumentValue, options); } + ObjectDbCommandBuilder IUpsertHelper.OnInsertOrUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpsertOptions options) + { + return new PostgreSqlInsertOrUpdateObject(this, tableName, argumentValue, options); + } + MultipleRowDbCommandBuilder IUpdateDeleteByKeyHelper.OnUpdateByKeyList(AbstractObjectName tableName, TArgument newValues, IEnumerable keys, UpdateOptions options) { var primaryKeys = DatabaseMetadata.GetTableOrView(tableName).PrimaryKeyColumns; @@ -173,7 +186,6 @@ MultipleRowDbCommandBuilder IUpdateDeleteByK } return new PostgreSqlUpdateSet(this, tableName, newValues, where, parameters, parameters.Count, options); - } ObjectDbCommandBuilder IUpdateDeleteHelper.OnUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpdateOptions options) @@ -199,34 +211,6 @@ IUpdateSetDbCommandBuilder IUpdateDeleteSetH return Sql("DELETE FROM " + table.Name.ToQuotedString() + ";").AsNonQuery(); } - private partial MultipleTableDbCommandBuilder OnSql(string sqlStatement, object? argumentValue) - { - return new PostgreSqlSqlCall(this, sqlStatement, argumentValue); - } - - private partial ILink OnTruncate(AbstractObjectName tableName) - { - //Verify the table name actually exists. - var table = DatabaseMetadata.GetTableOrView(tableName); - return Sql("TRUNCATE TABLE " + table.Name.ToQuotedString() + ";").AsNonQuery(); - } - - ObjectDbCommandBuilder IUpsertHelper.OnInsertOrUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpsertOptions options) - { - return new PostgreSqlInsertOrUpdateObject(this, tableName, argumentValue, options); - } - - PostgreSqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, DataTable dataTable) - { - return new PostgreSqlInsertBulk(this, tableName, dataTable); - } - - PostgreSqlInsertBulk IInsertBulkHelper.OnInsertBulk(AbstractObjectName tableName, IDataReader dataReader) - { - return new PostgreSqlInsertBulk(this, tableName, dataReader); - } - - private partial ProcedureDbCommandBuilder OnProcedure(AbstractObjectName procedureName, object? argumentValue) { return new AbstractProcedureCall(this, procedureName, argumentValue); @@ -237,8 +221,20 @@ private partial ScalarDbCommandBuilder OnSca return new AbstractScalarFunction(this, scalarFunctionName, argumentValue); } + private partial MultipleTableDbCommandBuilder OnSql(string sqlStatement, object? argumentValue) + { + return new PostgreSqlSqlCall(this, sqlStatement, argumentValue); + } + private partial TableDbCommandBuilder OnTableFunction(AbstractObjectName tableFunctionName, object? functionArgumentValue) { return new AbstractTableFunction(this, tableFunctionName, functionArgumentValue); } -} + + private partial ILink OnTruncate(AbstractObjectName tableName) + { + //Verify the table name actually exists. + var table = DatabaseMetadata.GetTableOrView(tableName); + return Sql("TRUNCATE TABLE " + table.Name.ToQuotedString() + ";").AsNonQuery(); + } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlMetadataCache.cs index c931b4d7c..412f0483c 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/PostgreSqlMetadataCache.cs @@ -9,166 +9,166 @@ using Tortuga.Anchor; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.PostgreSql +namespace Tortuga.Chain.PostgreSql; + +/// +/// Class PostgreSqlMetadataCache. +/// +public class PostgreSqlMetadataCache : DatabaseMetadataCache { + readonly NpgsqlConnectionStringBuilder m_ConnectionBuilder; + readonly ConcurrentDictionary> m_ScalarFunctions = new(); + readonly ConcurrentDictionary> m_StoredProcedures = new(); + readonly ConcurrentDictionary> m_TableFunctions = new(); + readonly ConcurrentDictionary> m_Tables = new(); + readonly ConcurrentDictionary> m_TypeTableMap = new(); + string? m_DatabaseName; + ImmutableArray m_DefaultSchemaList; + ImmutableDictionary>? m_SequenceColumns; + Version? m_ServerVersion; + string? m_ServerVersionName; + + static Regex s_DecimalMatcher = new Regex(@"\d", RegexOptions.Compiled); + /// - /// Class PostgreSqlMetadataCache. + /// Initializes a new instance of the class. /// - public class PostgreSqlMetadataCache : DatabaseMetadataCache + /// The connection builder. + public PostgreSqlMetadataCache(NpgsqlConnectionStringBuilder connectionBuilder) { - readonly NpgsqlConnectionStringBuilder m_ConnectionBuilder; - readonly ConcurrentDictionary> m_ScalarFunctions = new ConcurrentDictionary>(); - readonly ConcurrentDictionary> m_StoredProcedures = new ConcurrentDictionary>(); - readonly ConcurrentDictionary> m_TableFunctions = new ConcurrentDictionary>(); - readonly ConcurrentDictionary> m_Tables = new ConcurrentDictionary>(); - readonly ConcurrentDictionary> m_TypeTableMap = new ConcurrentDictionary>(); - string? m_DatabaseName; - ImmutableArray m_DefaultSchemaList; - ImmutableDictionary>? m_SequenceColumns; - Version? m_ServerVersion; - string? m_ServerVersionName; - - static Regex s_DecimalMatcher = new Regex(@"\d", RegexOptions.Compiled); - - /// - /// Initializes a new instance of the class. - /// - /// The connection builder. - public PostgreSqlMetadataCache(NpgsqlConnectionStringBuilder connectionBuilder) - { - m_ConnectionBuilder = connectionBuilder; - } + m_ConnectionBuilder = connectionBuilder; + } - /// - /// Returns the current database. - /// - /// - public string DatabaseName + /// + /// Returns the current database. + /// + /// + public string DatabaseName + { + get { - get + if (m_DatabaseName == null) { - if (m_DatabaseName == null) + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new NpgsqlCommand("select current_database()", con)) { - con.Open(); - using (var cmd = new NpgsqlCommand("select current_database()", con)) - { - m_DatabaseName = (string)cmd.ExecuteScalar()!; - } + m_DatabaseName = (string)cmd.ExecuteScalar()!; } } - return m_DatabaseName; } + return m_DatabaseName; } + } - /// - /// Returns the user's default schema. - /// - /// - public ImmutableArray DefaultSchemaList + /// + /// Returns the user's default schema. + /// + /// + public ImmutableArray DefaultSchemaList + { + get { - get + if (m_DefaultSchemaList == default) { - if (m_DefaultSchemaList == default) + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); + con.Open(); - string currentUser; - string defaultSchema; + string currentUser; + string defaultSchema; - using (var cmd = new NpgsqlCommand("select current_user;", con)) - { - currentUser = (string)cmd.ExecuteScalar()!; - } + using (var cmd = new NpgsqlCommand("select current_user;", con)) + { + currentUser = (string)cmd.ExecuteScalar()!; + } - using (var cmd = new NpgsqlCommand("SHOW search_path;", con)) - { - defaultSchema = (string)cmd.ExecuteScalar()!; - } - defaultSchema = defaultSchema.Replace("\"$user\"", currentUser); - m_DefaultSchemaList = defaultSchema.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToImmutableArray(); + using (var cmd = new NpgsqlCommand("SHOW search_path;", con)) + { + defaultSchema = (string)cmd.ExecuteScalar()!; } + defaultSchema = defaultSchema.Replace("\"$user\"", currentUser); + m_DefaultSchemaList = defaultSchema.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToImmutableArray(); } - return m_DefaultSchemaList; } + return m_DefaultSchemaList; } + } - /// - /// Gets the server version number. - /// - public override Version ServerVersion + /// + /// Gets the server version number. + /// + public override Version ServerVersion + { + get { - get + if (m_ServerVersion == null) { - if (m_ServerVersion == null) + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); + con.Open(); - using (var cmd = new NpgsqlCommand("SHOW server_version;", con)) - { - var versionString = (string)cmd.ExecuteScalar()!; - if (versionString.Contains(" ", StringComparison.Ordinal)) - versionString = versionString.Substring(0, versionString.IndexOf(" ", StringComparison.Ordinal)); - m_ServerVersion = Version.Parse(versionString); - } + using (var cmd = new NpgsqlCommand("SHOW server_version;", con)) + { + var versionString = (string)cmd.ExecuteScalar()!; + if (versionString.Contains(" ", StringComparison.Ordinal)) + versionString = versionString.Substring(0, versionString.IndexOf(" ", StringComparison.Ordinal)); + m_ServerVersion = Version.Parse(versionString); } } - return m_ServerVersion; } + return m_ServerVersion; } + } - /// - /// Gets the server version name. - /// - public override string ServerVersionName + /// + /// Gets the server version name. + /// + public override string ServerVersionName + { + get { - get + if (m_ServerVersionName == null) { - if (m_ServerVersionName == null) + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); + con.Open(); - using (var cmd = new NpgsqlCommand("SELECT version();", con)) - m_ServerVersionName = (string)cmd.ExecuteScalar()!; - } + using (var cmd = new NpgsqlCommand("SELECT version();", con)) + m_ServerVersionName = (string)cmd.ExecuteScalar()!; } - return m_ServerVersionName; } + return m_ServerVersionName; } + } - /// - /// Gets the indexes for a table. - /// - /// Name of the table. - /// - /// - /// This should be cached on a TableOrViewMetadata object. - /// - public override IndexMetadataCollection GetIndexesForTable(PostgreSqlObjectName tableName) - { - string indexSql; + /// + /// Gets the indexes for a table. + /// + /// Name of the table. + /// + /// + /// This should be cached on a TableOrViewMetadata object. + /// + public override IndexMetadataCollection GetIndexesForTable(PostgreSqlObjectName tableName) + { + string indexSql; - if (ServerVersion.Major < 11) //no included columns - { - indexSql = + if (ServerVersion.Major < 11) //no included columns + { + indexSql = @"SELECT - idx.indexrelid as index_oid, + idx.indexrelid as index_oid, ns.nspname as schema_name, tab.relname as table_name, - cls.relname as index_name, - am.amname as index_type, + cls.relname as index_name, + am.amname as index_type, idx.indisprimary as is_primary, idx.indisunique as is_unique, - idx.indkey as column_indices, - idx.indnatts as key_column_count, - idx.indoption as column_options + idx.indkey as column_indices, + idx.indnatts as key_column_count, + idx.indoption as column_options FROM pg_index idx INNER JOIN pg_class cls ON cls.oid=idx.indexrelid @@ -176,21 +176,21 @@ pg_index idx INNER JOIN pg_am am ON am.oid=cls.relam INNER JOIN pg_namespace ns on ns.oid=tab.relnamespace WHERE ns.nspname = @Schema AND tab.relname = @Name"; - } - else - { - indexSql = + } + else + { + indexSql = @"SELECT - idx.indexrelid as index_oid, + idx.indexrelid as index_oid, ns.nspname as schema_name, tab.relname as table_name, - cls.relname as index_name, - am.amname as index_type, + cls.relname as index_name, + am.amname as index_type, idx.indisprimary as is_primary, idx.indisunique as is_unique, - idx.indkey as column_indices, - idx.indnkeyatts as key_column_count, - idx.indoption as column_options + idx.indkey as column_indices, + idx.indnkeyatts as key_column_count, + idx.indoption as column_options FROM pg_index idx INNER JOIN pg_class cls ON cls.oid=idx.indexrelid @@ -198,420 +198,420 @@ pg_index idx INNER JOIN pg_am am ON am.oid=cls.relam INNER JOIN pg_namespace ns on ns.oid=tab.relnamespace WHERE ns.nspname = @Schema AND tab.relname = @Name"; - } + } - var table = GetTableOrView(tableName); + var table = GetTableOrView(tableName); - var results = new List>(); - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) - using (var con2 = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + var results = new List>(); + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con2 = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + con2.Open(); + using (var cmd = new NpgsqlCommand(indexSql, con)) { - con.Open(); - con2.Open(); - using (var cmd = new NpgsqlCommand(indexSql, con)) + cmd.Parameters.AddWithValue("@Schema", tableName.Schema!); + cmd.Parameters.AddWithValue("@Name", tableName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableName.Schema!); - cmd.Parameters.AddWithValue("@Name", tableName.Name); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var indexOid = reader.GetUInt32("index_oid"); - var name = reader.GetString("index_name"); - var isUnique = reader.GetBoolean("is_unique"); + var indexOid = reader.GetUInt32("index_oid"); + var name = reader.GetString("index_name"); + var isUnique = reader.GetBoolean("is_unique"); - var isPrimaryKey = reader.GetBoolean("is_primary"); - var isUniqueConstraint = false; //TASk-285: Identify unique indexes that are also unique constraints - var keyColumnCount = reader.GetInt16("key_column_count"); + var isPrimaryKey = reader.GetBoolean("is_primary"); + var isUniqueConstraint = false; //TASk-285: Identify unique indexes that are also unique constraints + var keyColumnCount = reader.GetInt16("key_column_count"); - //Task-284: Index size + //Task-284: Index size - IndexType indexType; - switch (reader.GetString("index_type")) - { - case "btree": indexType = IndexType.BTree; break; - case "hash": indexType = IndexType.Hash; break; - case "gist": indexType = IndexType.Gist; break; - case "gin": indexType = IndexType.Gin; break; - case "spgist": indexType = IndexType.Spgist; break; - case "brin": indexType = IndexType.Brin; break; - default: indexType = IndexType.Unknown; break; - } + IndexType indexType; + switch (reader.GetString("index_type")) + { + case "btree": indexType = IndexType.BTree; break; + case "hash": indexType = IndexType.Hash; break; + case "gist": indexType = IndexType.Gist; break; + case "gin": indexType = IndexType.Gin; break; + case "spgist": indexType = IndexType.Spgist; break; + case "brin": indexType = IndexType.Brin; break; + default: indexType = IndexType.Unknown; break; + } - var columnIndices = reader.GetValue("column_indices"); - var descendingColumns = new Dictionary(); + var columnIndices = reader.GetValue("column_indices"); + var descendingColumns = new Dictionary(); - var columnSql = @"SELECT p.colIndex, pg_index_column_has_property(@Oid,p.colIndex,'desc') AS descending from generate_series(1, @IndexCount) p(colIndex)"; + var columnSql = @"SELECT p.colIndex, pg_index_column_has_property(@Oid,p.colIndex,'desc') AS descending from generate_series(1, @IndexCount) p(colIndex)"; - using (var cmd2 = new NpgsqlCommand(columnSql, con2)) + using (var cmd2 = new NpgsqlCommand(columnSql, con2)) + { + cmd2.Parameters.AddWithValue("@Oid", NpgsqlDbType.Oid, indexOid); + cmd2.Parameters.AddWithValue("@IndexCount", columnIndices.Length); + using (var reader2 = cmd2.ExecuteReader()) { - cmd2.Parameters.AddWithValue("@Oid", NpgsqlDbType.Oid, indexOid); - cmd2.Parameters.AddWithValue("@IndexCount", columnIndices.Length); - using (var reader2 = cmd2.ExecuteReader()) + while (reader2.Read()) { - while (reader2.Read()) - { - descendingColumns[reader2.GetInt32("colIndex")] = reader2.GetBooleanOrNull("descending"); - //Other column properties can be added here - } + descendingColumns[reader2.GetInt32("colIndex")] = reader2.GetBooleanOrNull("descending"); + //Other column properties can be added here } } + } - var columns = new List>(); - for (var i = 0; i < columnIndices.Length; i++) - { - //Note: The values in columnIndices is 1-based, so we need to offset it. - var column = table.Columns[columnIndices[i] - 1]; - var isIncluded = i < keyColumnCount; - var isDescending = descendingColumns[i + 1]; - - columns.Add(new IndexColumnMetadata(column, isDescending, isIncluded)); - } + var columns = new List>(); + for (var i = 0; i < columnIndices.Length; i++) + { + //Note: The values in columnIndices is 1-based, so we need to offset it. + var column = table.Columns[columnIndices[i] - 1]; + var isIncluded = i < keyColumnCount; + var isDescending = descendingColumns[i + 1]; - results.Add(new IndexMetadata(tableName, name, isPrimaryKey, isUnique, isUniqueConstraint, new IndexColumnMetadataCollection(columns), null, null, indexType)); + columns.Add(new IndexColumnMetadata(column, isDescending, isIncluded)); } + + results.Add(new IndexMetadata(tableName, name, isPrimaryKey, isUnique, isUniqueConstraint, new IndexColumnMetadataCollection(columns), null, null, indexType)); } } } - return new IndexMetadataCollection(results); } + return new IndexMetadataCollection(results); + } - /// - /// Gets the metadata for a scalar function. - /// - /// Name of the scalar function. - /// Null if the object could not be found. - public override ScalarFunctionMetadata GetScalarFunction(PostgreSqlObjectName scalarFunctionName) - { - return m_ScalarFunctions.GetOrAdd(scalarFunctionName, GetScalarFunctionInternal); - } + /// + /// Gets the metadata for a scalar function. + /// + /// Name of the scalar function. + /// Null if the object could not be found. + public override ScalarFunctionMetadata GetScalarFunction(PostgreSqlObjectName scalarFunctionName) + { + return m_ScalarFunctions.GetOrAdd(scalarFunctionName, GetScalarFunctionInternal); + } - /// - /// Gets the scalar functions that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetScalarFunctions() => m_ScalarFunctions.GetValues(); - - /// - /// Gets the stored procedure's metadata. - /// - /// Name of the procedure. - /// - /// - public override StoredProcedureMetadata GetStoredProcedure(PostgreSqlObjectName procedureName) - { - return m_StoredProcedures.GetOrAdd(procedureName, GetStoredProcedureInternal); - } + /// + /// Gets the scalar functions that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetScalarFunctions() => m_ScalarFunctions.GetValues(); - /// - /// Gets the stored procedures that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetStoredProcedures() => m_StoredProcedures.GetValues(); - - /// - /// Gets the metadata for a table function. - /// - /// Name of the table function. - /// - /// - public override TableFunctionMetadata GetTableFunction(PostgreSqlObjectName tableFunctionName) - { - return m_TableFunctions.GetOrAdd(tableFunctionName, GetTableFunctionInternal); - } + /// + /// Gets the stored procedure's metadata. + /// + /// Name of the procedure. + /// + /// + public override StoredProcedureMetadata GetStoredProcedure(PostgreSqlObjectName procedureName) + { + return m_StoredProcedures.GetOrAdd(procedureName, GetStoredProcedureInternal); + } - /// - /// Gets the table-valued functions that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetTableFunctions() => m_TableFunctions.GetValues(); - - /// - /// Gets the tables and views that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetTablesAndViews() - { - return m_Tables.GetValues(); - } + /// + /// Gets the stored procedures that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetStoredProcedures() => m_StoredProcedures.GetValues(); - /// - /// Preloads all of the metadata for this data source. - /// - public override void Preload() - { - PreloadTables(); - PreloadViews(); - PreloadTableFunctions(); - PreloadStoredProcedures(); - PreloadScalarFunctions(); - } + /// + /// Gets the metadata for a table function. + /// + /// Name of the table function. + /// + /// + public override TableFunctionMetadata GetTableFunction(PostgreSqlObjectName tableFunctionName) + { + return m_TableFunctions.GetOrAdd(tableFunctionName, GetTableFunctionInternal); + } - /// - /// Preloads the scalar functions. - /// - public void PreloadScalarFunctions() - { - const string TvfSql = @"SELECT routine_schema, routine_name FROM information_schema.routines where routine_type = 'FUNCTION' AND data_type<>'record';"; + /// + /// Gets the table-valued functions that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetTableFunctions() => m_TableFunctions.GetValues(); - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + /// + /// Gets the tables and views that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetTablesAndViews() + { + return m_Tables.GetValues(); + } + + /// + /// Preloads all of the metadata for this data source. + /// + public override void Preload() + { + PreloadTables(); + PreloadViews(); + PreloadTableFunctions(); + PreloadStoredProcedures(); + PreloadScalarFunctions(); + } + + /// + /// Preloads the scalar functions. + /// + public void PreloadScalarFunctions() + { + const string TvfSql = @"SELECT routine_schema, routine_name FROM information_schema.routines where routine_type = 'FUNCTION' AND data_type<>'record';"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new NpgsqlCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new NpgsqlCommand(TvfSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("routine_schema"); - var name = reader.GetString("routine_name"); - GetScalarFunction(new PostgreSqlObjectName(schema, name)); - } + var schema = reader.GetString("routine_schema"); + var name = reader.GetString("routine_name"); + GetScalarFunction(new PostgreSqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the table value functions. - /// - public void PreloadStoredProcedures() - { - const string procSql = @"SELECT routine_schema, routine_name FROM information_schema.routines where routine_type = 'FUNCTION' AND data_type='refcursor';"; + /// + /// Preloads the table value functions. + /// + public void PreloadStoredProcedures() + { + const string procSql = @"SELECT routine_schema, routine_name FROM information_schema.routines where routine_type = 'FUNCTION' AND data_type='refcursor';"; - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new NpgsqlCommand(procSql, con)) { - con.Open(); - using (var cmd = new NpgsqlCommand(procSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("routine_schema"); - var name = reader.GetString("routine_name"); - GetStoredProcedure(new PostgreSqlObjectName(schema, name)); - } + var schema = reader.GetString("routine_schema"); + var name = reader.GetString("routine_name"); + GetStoredProcedure(new PostgreSqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the table value functions. - /// - public void PreloadTableFunctions() - { - const string TvfSql = @"SELECT routine_schema, routine_name FROM information_schema.routines where routine_type = 'FUNCTION' AND data_type='record';"; + /// + /// Preloads the table value functions. + /// + public void PreloadTableFunctions() + { + const string TvfSql = @"SELECT routine_schema, routine_name FROM information_schema.routines where routine_type = 'FUNCTION' AND data_type='record';"; - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new NpgsqlCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new NpgsqlCommand(TvfSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("routine_schema"); - var name = reader.GetString("routine_name"); - GetTableFunction(new PostgreSqlObjectName(schema, name)); - } + var schema = reader.GetString("routine_schema"); + var name = reader.GetString("routine_name"); + GetTableFunction(new PostgreSqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the metadata for all tables. - /// - public void PreloadTables() + /// + /// Preloads the metadata for all tables. + /// + public void PreloadTables() + { + const string TableSql = + @"SELECT + table_schema as schemaname, + table_name as tablename, + table_type as type + FROM information_schema.tables + WHERE table_type='BASE TABLE' AND + table_schema<>'pg_catalog' AND + table_schema<>'information_schema';"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - const string TableSql = - @"SELECT - table_schema as schemaname, - table_name as tablename, - table_type as type - FROM information_schema.tables - WHERE table_type='BASE TABLE' AND - table_schema<>'pg_catalog' AND - table_schema<>'information_schema';"; - - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new NpgsqlCommand(TableSql, con)) { - con.Open(); - using (var cmd = new NpgsqlCommand(TableSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("schemaname"); - var name = reader.GetString("tablename"); - GetTableOrView(new PostgreSqlObjectName(schema, name)); - } + var schema = reader.GetString("schemaname"); + var name = reader.GetString("tablename"); + GetTableOrView(new PostgreSqlObjectName(schema, name)); } } } } + } - /// - /// Preloads the metadata for all views. - /// - public void PreloadViews() + /// + /// Preloads the metadata for all views. + /// + public void PreloadViews() + { + const string ViewSql = + @"SELECT + table_schema as schemaname, + table_name as tablename, + table_type as type + FROM information_schema.tables + WHERE table_type='VIEW' AND + table_schema<>'pg_catalog' AND + table_schema<>'information_schema';"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - const string ViewSql = - @"SELECT - table_schema as schemaname, - table_name as tablename, - table_type as type - FROM information_schema.tables - WHERE table_type='VIEW' AND - table_schema<>'pg_catalog' AND - table_schema<>'information_schema';"; - - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new NpgsqlCommand(ViewSql, con)) { - con.Open(); - using (var cmd = new NpgsqlCommand(ViewSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("schemaname"); - var name = reader.GetString("tablename"); - GetTableOrView(new PostgreSqlObjectName(schema, name)); - } + var schema = reader.GetString("schemaname"); + var name = reader.GetString("tablename"); + GetTableOrView(new PostgreSqlObjectName(schema, name)); } } } } + } - /// - /// Resets the metadata cache, clearing out all cached metadata. - /// - public override void Reset() - { - m_DatabaseName = null; - m_DefaultSchemaList = default; - m_SequenceColumns = null; - m_StoredProcedures.Clear(); - m_TableFunctions.Clear(); - m_Tables.Clear(); - m_TypeTableMap.Clear(); - m_ScalarFunctions.Clear(); - } + /// + /// Resets the metadata cache, clearing out all cached metadata. + /// + public override void Reset() + { + m_DatabaseName = null; + m_DefaultSchemaList = default; + m_SequenceColumns = null; + m_StoredProcedures.Clear(); + m_TableFunctions.Clear(); + m_Tables.Clear(); + m_TypeTableMap.Clear(); + m_ScalarFunctions.Clear(); + } - /// - /// Determines the database column type from the column type name. - /// - /// Name of the database column type. - /// NOT USED - /// - /// This does not honor registered types. This is only used for the database's hard-coded list of native types. - [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - protected override NpgsqlDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) - { - if (string.IsNullOrEmpty(typeName)) - throw new ArgumentException($"{nameof(typeName)} is null or empty.", nameof(typeName)); + /// + /// Determines the database column type from the column type name. + /// + /// Name of the database column type. + /// NOT USED + /// + /// This does not honor registered types. This is only used for the database's hard-coded list of native types. + [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + protected override NpgsqlDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) + { + if (string.IsNullOrEmpty(typeName)) + throw new ArgumentException($"{nameof(typeName)} is null or empty.", nameof(typeName)); #pragma warning disable CS0618 // Type or member is obsolete - switch (typeName.ToUpperInvariant().Replace("_", "").Replace("\"", "")) - { - case "ABSTIME": return NpgsqlDbType.Abstime; - case "ARRAY": return NpgsqlDbType.Array; - case "BIGINT": return NpgsqlDbType.Bigint; - case "BIT": return NpgsqlDbType.Bit; - case "BOOL": return NpgsqlDbType.Boolean; - case "BOOLEAN": return NpgsqlDbType.Boolean; - case "BOX": return NpgsqlDbType.Box; - case "BYTEA": return NpgsqlDbType.Bytea; - case "CHAR": return NpgsqlDbType.Char; - case "CHARACTER": - case "CID": return NpgsqlDbType.Cid; - case "CIDR": return NpgsqlDbType.Cidr; - case "CIRCLE": return NpgsqlDbType.Circle; - case "CITEXT": return NpgsqlDbType.Citext; - case "DATE": return NpgsqlDbType.Date; - case "DOUBLE": return NpgsqlDbType.Double; - case "DOUBLE PRECISION": return NpgsqlDbType.Double; - case "FLOAT4": return NpgsqlDbType.Real; - case "FLOAT8": return NpgsqlDbType.Double; - case "GEOGRAPHY": return NpgsqlDbType.Geography; - case "GEOMETRY": return NpgsqlDbType.Geometry; - case "HSTORE": return NpgsqlDbType.Hstore; - case "INET": return NpgsqlDbType.Inet; - case "INT2": return NpgsqlDbType.Smallint; - case "INT2VECTOR": return NpgsqlDbType.Int2Vector; - case "INT4": return NpgsqlDbType.Integer; - case "INT8": return NpgsqlDbType.Bigint; - case "INTEGER": return NpgsqlDbType.Integer; - case "INTERVAL": return NpgsqlDbType.Interval; - case "JSON": return NpgsqlDbType.Json; - case "JSONB": return NpgsqlDbType.Jsonb; - case "LINE": return NpgsqlDbType.Line; - case "LSEG": return NpgsqlDbType.LSeg; - case "MACADDR": return NpgsqlDbType.MacAddr; - case "MACADDR8": return NpgsqlDbType.MacAddr8; - case "MONEY": return NpgsqlDbType.Money; - case "NAME": return NpgsqlDbType.Name; - case "NUMERIC": return NpgsqlDbType.Numeric; - case "OID": return NpgsqlDbType.Oid; - case "OIDVECTOR": return NpgsqlDbType.Oidvector; - case "PATH": return NpgsqlDbType.Path; - case "POINT": return NpgsqlDbType.Point; - case "POLYGON": return NpgsqlDbType.Polygon; - case "RANGE": return NpgsqlDbType.Range; - case "REAL": return NpgsqlDbType.Real; - case "REFCURSOR": return NpgsqlDbType.Refcursor; - case "REGCONFIG": return NpgsqlDbType.Regconfig; - case "REGTYPE": return NpgsqlDbType.Regtype; - case "SMALLINT": return NpgsqlDbType.Smallint; - case "TEXT": return NpgsqlDbType.Text; - case "TID": return NpgsqlDbType.Tid; - case "TIME WITH TIME ZONE": return NpgsqlDbType.TimeTz; - case "TIMETZ": return NpgsqlDbType.TimeTz; - case "TIME": return NpgsqlDbType.Time; - case "TIME WITHOUT TIME ZONE": return NpgsqlDbType.Time; - case "TIMESTAMP WITH TIME ZONE": return NpgsqlDbType.TimestampTz; - case "TIMESTAMPTZ": return NpgsqlDbType.TimestampTz; - case "TIMESTAMP": return NpgsqlDbType.Timestamp; - case "TIMESTAMP WITHOUT TIME ZONE": return NpgsqlDbType.Timestamp; - case "TSQUERY": return NpgsqlDbType.TsQuery; - case "TSVECTOR": return NpgsqlDbType.TsVector; - case "UUID": return NpgsqlDbType.Uuid; - case "VARBIT": return NpgsqlDbType.Varbit; - case "BIT VARYING": return NpgsqlDbType.Varbit; - case "VARCHAR": return NpgsqlDbType.Varchar; - case "CHARACTER VARYING": return NpgsqlDbType.Varchar; - case "XID": return NpgsqlDbType.Xid; - case "XML": return NpgsqlDbType.Xml; - default: return null; - } -#pragma warning restore CS0618 // Type or member is obsolete + switch (typeName.ToUpperInvariant().Replace("_", "").Replace("\"", "")) + { + case "ABSTIME": return NpgsqlDbType.Abstime; + case "ARRAY": return NpgsqlDbType.Array; + case "BIGINT": return NpgsqlDbType.Bigint; + case "BIT": return NpgsqlDbType.Bit; + case "BOOL": return NpgsqlDbType.Boolean; + case "BOOLEAN": return NpgsqlDbType.Boolean; + case "BOX": return NpgsqlDbType.Box; + case "BYTEA": return NpgsqlDbType.Bytea; + case "CHAR": return NpgsqlDbType.Char; + case "CHARACTER": + case "CID": return NpgsqlDbType.Cid; + case "CIDR": return NpgsqlDbType.Cidr; + case "CIRCLE": return NpgsqlDbType.Circle; + case "CITEXT": return NpgsqlDbType.Citext; + case "DATE": return NpgsqlDbType.Date; + case "DOUBLE": return NpgsqlDbType.Double; + case "DOUBLE PRECISION": return NpgsqlDbType.Double; + case "FLOAT4": return NpgsqlDbType.Real; + case "FLOAT8": return NpgsqlDbType.Double; + case "GEOGRAPHY": return NpgsqlDbType.Geography; + case "GEOMETRY": return NpgsqlDbType.Geometry; + case "HSTORE": return NpgsqlDbType.Hstore; + case "INET": return NpgsqlDbType.Inet; + case "INT2": return NpgsqlDbType.Smallint; + case "INT2VECTOR": return NpgsqlDbType.Int2Vector; + case "INT4": return NpgsqlDbType.Integer; + case "INT8": return NpgsqlDbType.Bigint; + case "INTEGER": return NpgsqlDbType.Integer; + case "INTERVAL": return NpgsqlDbType.Interval; + case "JSON": return NpgsqlDbType.Json; + case "JSONB": return NpgsqlDbType.Jsonb; + case "LINE": return NpgsqlDbType.Line; + case "LSEG": return NpgsqlDbType.LSeg; + case "MACADDR": return NpgsqlDbType.MacAddr; + case "MACADDR8": return NpgsqlDbType.MacAddr8; + case "MONEY": return NpgsqlDbType.Money; + case "NAME": return NpgsqlDbType.Name; + case "NUMERIC": return NpgsqlDbType.Numeric; + case "OID": return NpgsqlDbType.Oid; + case "OIDVECTOR": return NpgsqlDbType.Oidvector; + case "PATH": return NpgsqlDbType.Path; + case "POINT": return NpgsqlDbType.Point; + case "POLYGON": return NpgsqlDbType.Polygon; + case "RANGE": return NpgsqlDbType.Range; + case "REAL": return NpgsqlDbType.Real; + case "REFCURSOR": return NpgsqlDbType.Refcursor; + case "REGCONFIG": return NpgsqlDbType.Regconfig; + case "REGTYPE": return NpgsqlDbType.Regtype; + case "SMALLINT": return NpgsqlDbType.Smallint; + case "TEXT": return NpgsqlDbType.Text; + case "TID": return NpgsqlDbType.Tid; + case "TIME WITH TIME ZONE": return NpgsqlDbType.TimeTz; + case "TIMETZ": return NpgsqlDbType.TimeTz; + case "TIME": return NpgsqlDbType.Time; + case "TIME WITHOUT TIME ZONE": return NpgsqlDbType.Time; + case "TIMESTAMP WITH TIME ZONE": return NpgsqlDbType.TimestampTz; + case "TIMESTAMPTZ": return NpgsqlDbType.TimestampTz; + case "TIMESTAMP": return NpgsqlDbType.Timestamp; + case "TIMESTAMP WITHOUT TIME ZONE": return NpgsqlDbType.Timestamp; + case "TSQUERY": return NpgsqlDbType.TsQuery; + case "TSVECTOR": return NpgsqlDbType.TsVector; + case "UUID": return NpgsqlDbType.Uuid; + case "VARBIT": return NpgsqlDbType.Varbit; + case "BIT VARYING": return NpgsqlDbType.Varbit; + case "VARCHAR": return NpgsqlDbType.Varchar; + case "CHARACTER VARYING": return NpgsqlDbType.Varchar; + case "XID": return NpgsqlDbType.Xid; + case "XML": return NpgsqlDbType.Xml; + default: return null; } +#pragma warning restore CS0618 // Type or member is obsolete + } - /// - /// Gets a list of known, unsupported SQL type names that cannot be mapped to a NpgsqlDbType. - /// - /// Case-insensitive list of database-specific type names - /// This list is based on driver limitations. - public override ImmutableHashSet UnsupportedSqlTypeNames { get; } = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, new[] { "trigger", "internal", "regclass", "bpchar", "pg_lsn", "void", "cstring", "reltime", "anyenum", "anyarray", "anyelement", "anyrange", "_regdictionary", "any", "regdictionary", "tstzrange" , - "jsonpath","pg_mcv_list","table_am_handler", + /// + /// Gets a list of known, unsupported SQL type names that cannot be mapped to a NpgsqlDbType. + /// + /// Case-insensitive list of database-specific type names + /// This list is based on driver limitations. + public override ImmutableHashSet UnsupportedSqlTypeNames { get; } = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, new[] { "trigger", "internal", "regclass", "bpchar", "pg_lsn", "void", "cstring", "reltime", "anyenum", "anyarray", "anyelement", "anyrange", "_regdictionary", "any", "regdictionary", "tstzrange" , + "jsonpath","pg_mcv_list","table_am_handler", "ANYNONARRAY", "UNKNOWN", "PG_DDL_COMMAND", @@ -663,362 +663,361 @@ public override void Reset() "int4multirange", "nummultirange", "tstzmultirange" + }); - }); + /// + /// Parse a string and return the database specific representation of the object name. + /// + /// The schema. + /// The name. + /// PostgreSqlObjectName. + protected override PostgreSqlObjectName ParseObjectName(string? schema, string name) + { + if (schema == null) + return new PostgreSqlObjectName(name); + return new PostgreSqlObjectName(schema, name); + } - /// - /// Parse a string and return the database specific representation of the object name. - /// - /// The schema. - /// The name. - /// PostgreSqlObjectName. - protected override PostgreSqlObjectName ParseObjectName(string? schema, string name) - { - if (schema == null) - return new PostgreSqlObjectName(name); - return new PostgreSqlObjectName(schema, name); - } + Tuple, ColumnMetadataCollection> GetParametersAndColumns(string specificName, NpgsqlConnection connection) + { + const string parameterSql = @"SELECT * FROM information_schema.parameters WHERE specific_name = @SpecificName ORDER BY ordinal_position"; - Tuple, ColumnMetadataCollection> GetParametersAndColumns(string specificName, NpgsqlConnection connection) + var parameters = new List>(); + var columns = new List>(); + using (var cmd = new NpgsqlCommand(parameterSql, connection)) { - const string parameterSql = @"SELECT * FROM information_schema.parameters WHERE specific_name = @SpecificName ORDER BY ordinal_position"; - - var parameters = new List>(); - var columns = new List>(); - using (var cmd = new NpgsqlCommand(parameterSql, connection)) + cmd.Parameters.AddWithValue("@SpecificName", specificName); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@SpecificName", specificName); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) + if (string.Equals(reader.GetString("parameter_mode"), "IN", StringComparison.Ordinal)) { - if (string.Equals(reader.GetString("parameter_mode"), "IN", StringComparison.Ordinal)) - { - var parameterName = reader.GetStringOrNull("parameter_name") ?? "Parameter" + reader.GetInt32("ordinal_position"); + var parameterName = reader.GetStringOrNull("parameter_name") ?? "Parameter" + reader.GetInt32("ordinal_position"); + + var typeName = reader.GetString("udt_name"); + bool isNullable = true; + int? maxLength = null; + int? precision = null; + int? scale = null; + string fullTypeName = ""; //Task-291: Add support for full name - var typeName = reader.GetString("udt_name"); - bool isNullable = true; - int? maxLength = null; - int? precision = null; - int? scale = null; - string fullTypeName = ""; //Task-291: Add support for full name + //Task-120: Add support for length, precision, and scale + //Task-384: OUTPUT Parameters for PostgreSQL + var direction = ParameterDirection.Input; - //Task-120: Add support for length, precision, and scale - //Task-384: OUTPUT Parameters for PostgreSQL - var direction = ParameterDirection.Input; + parameters.Add(new ParameterMetadata(parameterName, "@" + parameterName, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName, direction)); + } + else + { + var name = reader.GetString("parameter_name"); + var typeName = reader.GetString("udt_name"); + bool isPrimary = false; + bool isIdentity = false; + bool? isNullable = null; + int? maxLength = null; + int? precision = null; + int? scale = null; + string fullTypeName = ""; //Task-291: Add support for full name - parameters.Add(new ParameterMetadata(parameterName, "@" + parameterName, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName, direction)); - } - else - { - var name = reader.GetString("parameter_name"); - var typeName = reader.GetString("udt_name"); - bool isPrimary = false; - bool isIdentity = false; - bool? isNullable = null; - int? maxLength = null; - int? precision = null; - int? scale = null; - string fullTypeName = ""; //Task-291: Add support for full name - - //Task-120: Add support for length, precision, and scale - - columns.Add(new ColumnMetadata(name, false, isPrimary, isIdentity, typeName, SqlTypeNameToDbType(typeName), "\"" + name + "\"", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable ?? true, maxLength))); - } + //Task-120: Add support for length, precision, and scale + + columns.Add(new ColumnMetadata(name, false, isPrimary, isIdentity, typeName, SqlTypeNameToDbType(typeName), "\"" + name + "\"", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable ?? true, maxLength))); } } } - return Tuple.Create(new ParameterMetadataCollection(specificName, parameters), new ColumnMetadataCollection(specificName, columns)); } + return Tuple.Create(new ParameterMetadataCollection(specificName, parameters), new ColumnMetadataCollection(specificName, columns)); + } - ColumnMetadataCollection GetColumns(PostgreSqlObjectName tableName, NpgsqlConnection connection) - { - string columnSql; + ColumnMetadataCollection GetColumns(PostgreSqlObjectName tableName, NpgsqlConnection connection) + { + string columnSql; - if (ServerVersion.Major < 10) //no attidentity - { - columnSql = - @" + if (ServerVersion.Major < 10) //no attidentity + { + columnSql = + @" SELECT att.attname as column_name, - t.typname as data_type, - pk.contype as is_primary_key, - att.attnotnull as not_null, - null as is_identity, - format_type(att.atttypid, att.atttypmod) as data_type_full + t.typname as data_type, + pk.contype as is_primary_key, + att.attnotnull as not_null, + null as is_identity, + format_type(att.atttypid, att.atttypmod) as data_type_full FROM pg_class as c JOIN pg_namespace as ns on ns.oid=c.relnamespace JOIN pg_attribute as att on c.oid=att.attrelid AND - att.attnum>0 + att.attnum>0 JOIN pg_type as t on t.oid=att.atttypid LEFT JOIN (SELECT cnst.conrelid, - cnst.conkey, - cnst.contype - FROM pg_constraint as cnst - WHERE cnst.contype='p') pk ON att.attnum=ANY(pk.conkey) AND - pk.conrelid=c.oid + cnst.conkey, + cnst.contype + FROM pg_constraint as cnst + WHERE cnst.contype='p') pk ON att.attnum=ANY(pk.conkey) AND + pk.conrelid=c.oid WHERE c.relname ILIKE @Name AND - ns.nspname ILIKE @Schema;"; - } - else - { - columnSql = + ns.nspname ILIKE @Schema;"; + } + else + { + columnSql = @" SELECT att.attname as column_name, - t.typname as data_type, - pk.contype as is_primary_key, - att.attnotnull as not_null, - att.attidentity as is_identity, - format_type(att.atttypid, att.atttypmod) as data_type_full + t.typname as data_type, + pk.contype as is_primary_key, + att.attnotnull as not_null, + att.attidentity as is_identity, + format_type(att.atttypid, att.atttypmod) as data_type_full FROM pg_class as c JOIN pg_namespace as ns on ns.oid=c.relnamespace JOIN pg_attribute as att on c.oid=att.attrelid AND - att.attnum>0 + att.attnum>0 JOIN pg_type as t on t.oid=att.atttypid LEFT JOIN (SELECT cnst.conrelid, - cnst.conkey, - cnst.contype - FROM pg_constraint as cnst - WHERE cnst.contype='p') pk ON att.attnum=ANY(pk.conkey) AND - pk.conrelid=c.oid + cnst.conkey, + cnst.contype + FROM pg_constraint as cnst + WHERE cnst.contype='p') pk ON att.attnum=ANY(pk.conkey) AND + pk.conrelid=c.oid WHERE c.relname ILIKE @Name AND - ns.nspname ILIKE @Schema;"; - } + ns.nspname ILIKE @Schema;"; + } - var columns = new List>(); - var sequenceColumns = GetSequenceColumns(tableName); + var columns = new List>(); + var sequenceColumns = GetSequenceColumns(tableName); - using (var cmd = new NpgsqlCommand(columnSql, connection)) + using (var cmd = new NpgsqlCommand(columnSql, connection)) + { + cmd.Parameters.AddWithValue("@Schema", tableName.Schema!); + cmd.Parameters.AddWithValue("@Name", tableName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableName.Schema!); - cmd.Parameters.AddWithValue("@Name", tableName.Name); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var name = reader.GetString("column_name"); - var typeName = reader.GetString("data_type"); - bool isPrimary = !reader.IsDBNull("is_primary_key"); + var name = reader.GetString("column_name"); + var typeName = reader.GetString("data_type"); + bool isPrimary = !reader.IsDBNull("is_primary_key"); - var identity_type = char.ToUpperInvariant(reader.GetCharOrNull("is_identity") ?? ' '); - var isIdentity = identity_type == 'A' || identity_type == 'D'; - if (!isIdentity) //check if its attached to a sequence - isIdentity = sequenceColumns.Contains(name); + var identity_type = char.ToUpperInvariant(reader.GetCharOrNull("is_identity") ?? ' '); + var isIdentity = identity_type == 'A' || identity_type == 'D'; + if (!isIdentity) //check if its attached to a sequence + isIdentity = sequenceColumns.Contains(name); - bool isNullable = !reader.GetBoolean("not_null"); + bool isNullable = !reader.GetBoolean("not_null"); - var dbType = SqlTypeNameToDbType(typeName); - var fullTypeName = reader.GetString("data_type_full"); + var dbType = SqlTypeNameToDbType(typeName); + var fullTypeName = reader.GetString("data_type_full"); - var match1 = s_DecimalMatcher.Match(fullTypeName); - var match2 = match1.Success ? match1.NextMatch() : null; - var value1 = match1.Success ? int.Parse(match1.Value, CultureInfo.InvariantCulture) : (int?)null; - var value2 = match2?.Success == true ? int.Parse(match2.Value, CultureInfo.InvariantCulture) : (int?)null; + var match1 = s_DecimalMatcher.Match(fullTypeName); + var match2 = match1.Success ? match1.NextMatch() : null; + var value1 = match1.Success ? int.Parse(match1.Value, CultureInfo.InvariantCulture) : (int?)null; + var value2 = match2?.Success == true ? int.Parse(match2.Value, CultureInfo.InvariantCulture) : (int?)null; - int? maxLength = null; - int? precision = null; - int? scale = null; - - switch (dbType) - { - case NpgsqlDbType.Char: - case NpgsqlDbType.Varchar: - case NpgsqlDbType.Bit: - case NpgsqlDbType.Varbit: - maxLength = value1; - break; - - case NpgsqlDbType.Time: - case NpgsqlDbType.TimeTz: - case NpgsqlDbType.Timestamp: - case NpgsqlDbType.TimestampTz: - precision = value1; - break; - - case NpgsqlDbType.Numeric: - precision = value1; - scale = value2; - if (precision.HasValue && scale == null) - scale = 0; - break; - } + int? maxLength = null; + int? precision = null; + int? scale = null; - columns.Add(new ColumnMetadata(name, false, isPrimary, isIdentity, typeName, dbType, "\"" + name + "\"", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, maxLength))); + switch (dbType) + { + case NpgsqlDbType.Char: + case NpgsqlDbType.Varchar: + case NpgsqlDbType.Bit: + case NpgsqlDbType.Varbit: + maxLength = value1; + break; + + case NpgsqlDbType.Time: + case NpgsqlDbType.TimeTz: + case NpgsqlDbType.Timestamp: + case NpgsqlDbType.TimestampTz: + precision = value1; + break; + + case NpgsqlDbType.Numeric: + precision = value1; + scale = value2; + if (precision.HasValue && scale == null) + scale = 0; + break; } + + columns.Add(new ColumnMetadata(name, false, isPrimary, isIdentity, typeName, dbType, "\"" + name + "\"", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, maxLength))); } } - - return new ColumnMetadataCollection(tableName.ToString(), columns); } - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Type of the database column. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. Defaults to string. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// This does not take into consideration registered types. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - protected override Type? ToClrType(NpgsqlDbType dbType, bool isNullable, int? maxLength) + return new ColumnMetadataCollection(tableName.ToString(), columns); + } + + /// + /// Returns the CLR type that matches the indicated database column type. + /// + /// Type of the database column. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. Defaults to string. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// This does not take into consideration registered types. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + protected override Type? ToClrType(NpgsqlDbType dbType, bool isNullable, int? maxLength) + { + switch (dbType) { - switch (dbType) - { - case NpgsqlDbType.Bigint: - return isNullable ? typeof(long?) : typeof(long); - - case NpgsqlDbType.Double: - return isNullable ? typeof(double?) : typeof(double); - - case NpgsqlDbType.Integer: - return isNullable ? typeof(int?) : typeof(int); - - case NpgsqlDbType.Numeric: - case NpgsqlDbType.Money: - return isNullable ? typeof(decimal?) : typeof(decimal); - - case NpgsqlDbType.Real: - return isNullable ? typeof(float?) : typeof(float); - - case NpgsqlDbType.Smallint: - return isNullable ? typeof(short?) : typeof(short); - - case NpgsqlDbType.Boolean: - return isNullable ? typeof(bool?) : typeof(bool); - - case NpgsqlDbType.Char: - case NpgsqlDbType.Varchar: - return (maxLength == 1) ? (isNullable ? typeof(char?) : typeof(char)) : typeof(string); - - case NpgsqlDbType.Text: - return typeof(string); - - case NpgsqlDbType.Bytea: - return typeof(byte[]); - - case NpgsqlDbType.Date: - case NpgsqlDbType.Timestamp: - return isNullable ? typeof(DateTime?) : typeof(DateTime); - - case NpgsqlDbType.Time: - return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); - - case NpgsqlDbType.Interval: - return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); - - case NpgsqlDbType.Bit: - return typeof(BitArray); - - case NpgsqlDbType.Uuid: - return isNullable ? typeof(Guid?) : typeof(Guid); - - case NpgsqlDbType.Xml: - case NpgsqlDbType.Json: - case NpgsqlDbType.Jsonb: - return typeof(string); - - case NpgsqlDbType.Inet: - case NpgsqlDbType.Cidr: - case NpgsqlDbType.MacAddr: - case NpgsqlDbType.MacAddr8: - case NpgsqlDbType.Varbit: - case NpgsqlDbType.TsVector: - case NpgsqlDbType.TsQuery: - case NpgsqlDbType.Regconfig: - case NpgsqlDbType.Hstore: - case NpgsqlDbType.Array: - case NpgsqlDbType.Range: - case NpgsqlDbType.Refcursor: - case NpgsqlDbType.Oidvector: - case NpgsqlDbType.Int2Vector: - case NpgsqlDbType.Oid: - case NpgsqlDbType.Xid: - case NpgsqlDbType.Cid: - case NpgsqlDbType.Regtype: - case NpgsqlDbType.Tid: - case NpgsqlDbType.Unknown: - case NpgsqlDbType.Geometry: - case NpgsqlDbType.Geography: - case NpgsqlDbType.Box: - case NpgsqlDbType.Circle: - case NpgsqlDbType.Line: - case NpgsqlDbType.LSeg: - case NpgsqlDbType.Path: - case NpgsqlDbType.Point: - case NpgsqlDbType.Polygon: - case NpgsqlDbType.Name: - case NpgsqlDbType.Citext: - case NpgsqlDbType.InternalChar: - return null; + case NpgsqlDbType.Bigint: + return isNullable ? typeof(long?) : typeof(long); + + case NpgsqlDbType.Double: + return isNullable ? typeof(double?) : typeof(double); + + case NpgsqlDbType.Integer: + return isNullable ? typeof(int?) : typeof(int); + + case NpgsqlDbType.Numeric: + case NpgsqlDbType.Money: + return isNullable ? typeof(decimal?) : typeof(decimal); + + case NpgsqlDbType.Real: + return isNullable ? typeof(float?) : typeof(float); + + case NpgsqlDbType.Smallint: + return isNullable ? typeof(short?) : typeof(short); + + case NpgsqlDbType.Boolean: + return isNullable ? typeof(bool?) : typeof(bool); + + case NpgsqlDbType.Char: + case NpgsqlDbType.Varchar: + return (maxLength == 1) ? (isNullable ? typeof(char?) : typeof(char)) : typeof(string); + + case NpgsqlDbType.Text: + return typeof(string); + + case NpgsqlDbType.Bytea: + return typeof(byte[]); + + case NpgsqlDbType.Date: + case NpgsqlDbType.Timestamp: + return isNullable ? typeof(DateTime?) : typeof(DateTime); + + case NpgsqlDbType.Time: + return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); + + case NpgsqlDbType.Interval: + return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); + + case NpgsqlDbType.Bit: + return typeof(BitArray); + + case NpgsqlDbType.Uuid: + return isNullable ? typeof(Guid?) : typeof(Guid); + + case NpgsqlDbType.Xml: + case NpgsqlDbType.Json: + case NpgsqlDbType.Jsonb: + return typeof(string); + + case NpgsqlDbType.Inet: + case NpgsqlDbType.Cidr: + case NpgsqlDbType.MacAddr: + case NpgsqlDbType.MacAddr8: + case NpgsqlDbType.Varbit: + case NpgsqlDbType.TsVector: + case NpgsqlDbType.TsQuery: + case NpgsqlDbType.Regconfig: + case NpgsqlDbType.Hstore: + case NpgsqlDbType.Array: + case NpgsqlDbType.Range: + case NpgsqlDbType.Refcursor: + case NpgsqlDbType.Oidvector: + case NpgsqlDbType.Int2Vector: + case NpgsqlDbType.Oid: + case NpgsqlDbType.Xid: + case NpgsqlDbType.Cid: + case NpgsqlDbType.Regtype: + case NpgsqlDbType.Tid: + case NpgsqlDbType.Unknown: + case NpgsqlDbType.Geometry: + case NpgsqlDbType.Geography: + case NpgsqlDbType.Box: + case NpgsqlDbType.Circle: + case NpgsqlDbType.Line: + case NpgsqlDbType.LSeg: + case NpgsqlDbType.Path: + case NpgsqlDbType.Point: + case NpgsqlDbType.Polygon: + case NpgsqlDbType.Name: + case NpgsqlDbType.Citext: + case NpgsqlDbType.InternalChar: + return null; #pragma warning disable CS0618 // Type or member is obsolete - case NpgsqlDbType.TimestampTZ: - return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); + case NpgsqlDbType.TimestampTZ: + return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); - case NpgsqlDbType.TimeTZ: - return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); + case NpgsqlDbType.TimeTZ: + return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); - case NpgsqlDbType.Abstime: - return null; + case NpgsqlDbType.Abstime: + return null; #pragma warning restore CS0618 // Type or member is obsolete - } - return null; } + return null; + } - ScalarFunctionMetadata GetScalarFunctionInternal(PostgreSqlObjectName tableFunctionName) + ScalarFunctionMetadata GetScalarFunctionInternal(PostgreSqlObjectName tableFunctionName) + { + const string functionSql = @"SELECT routine_schema, routine_name, specific_name, data_type FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND data_type<>'record' AND routine_schema ILIKE @Schema AND routine_name ILIKE @Name;"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - const string functionSql = @"SELECT routine_schema, routine_name, specific_name, data_type FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND data_type<>'record' AND routine_schema ILIKE @Schema AND routine_name ILIKE @Name;"; + con.Open(); - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + foreach (var schema in GetSchemasToCheck(tableFunctionName)) { - con.Open(); + string actualSchema; + string actualName; + string specificName; + string typeName; - foreach (var schema in GetSchemasToCheck(tableFunctionName)) + using (var cmd = new NpgsqlCommand(functionSql, con)) { - string actualSchema; - string actualName; - string specificName; - string typeName; - - using (var cmd = new NpgsqlCommand(functionSql, con)) + cmd.Parameters.AddWithValue("@Schema", schema); + cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", schema); - cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - continue; + if (!reader.Read()) + continue; - actualSchema = reader.GetString("routine_schema"); - actualName = reader.GetString("routine_name"); - specificName = reader.GetString("specific_name"); - typeName = reader.GetString("data_type"); - } + actualSchema = reader.GetString("routine_schema"); + actualName = reader.GetString("routine_name"); + specificName = reader.GetString("specific_name"); + typeName = reader.GetString("data_type"); } + } - var pAndC = GetParametersAndColumns(specificName, con); - bool isNullable = true; - int? maxLength = null; - int? precision = null; - int? scale = null; - string fullTypeName = ""; //Task-291: Add support for full name + var pAndC = GetParametersAndColumns(specificName, con); + bool isNullable = true; + int? maxLength = null; + int? precision = null; + int? scale = null; + string fullTypeName = ""; //Task-291: Add support for full name - //Task-120: Add support for length, precision, and scale for return type + //Task-120: Add support for length, precision, and scale for return type - return new ScalarFunctionMetadata(new PostgreSqlObjectName(actualSchema, actualName), pAndC.Item1, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName); - } + return new ScalarFunctionMetadata(new PostgreSqlObjectName(actualSchema, actualName), pAndC.Item1, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName); } - - throw new MissingObjectException($"Could not find scalar function {tableFunctionName}"); } - IEnumerable GetSchemasToCheck(PostgreSqlObjectName objectName) => objectName.Schema == null ? DefaultSchemaList : ImmutableArray.Create(objectName.Schema); + throw new MissingObjectException($"Could not find scalar function {tableFunctionName}"); + } - ImmutableHashSet GetSequenceColumns(PostgreSqlObjectName tableName) - { - const string sql = @"select s.relname as SequenceName, n.nspname as SchemaName, t.relname as TableName, a.attname as ColumnName + IEnumerable GetSchemasToCheck(PostgreSqlObjectName objectName) => objectName.Schema == null ? DefaultSchemaList : ImmutableArray.Create(objectName.Schema); + + ImmutableHashSet GetSequenceColumns(PostgreSqlObjectName tableName) + { + const string sql = @"select s.relname as SequenceName, n.nspname as SchemaName, t.relname as TableName, a.attname as ColumnName from pg_class s join pg_depend d on d.objid=s.oid and d.classid='pg_class'::regclass and d.refclassid='pg_class'::regclass join pg_class t on t.oid=d.refobjid @@ -1026,181 +1025,180 @@ from pg_class s join pg_attribute a on a.attrelid=t.oid and a.attnum=d.refobjsubid where s.relkind='S' and d.deptype='a'"; - if (m_SequenceColumns == null) + if (m_SequenceColumns == null) + { + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); + con.Open(); - using (var cmd = new NpgsqlCommand(sql, con)) + using (var cmd = new NpgsqlCommand(sql, con)) + { + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + var result = new Dictionary>(); + while (reader.Read()) { - var result = new Dictionary>(); - while (reader.Read()) - { - var schemaTableName = new PostgreSqlObjectName(reader.GetString("SchemaName"), reader.GetString("TableName")); - var columnName = reader.GetString("ColumnName"); + var schemaTableName = new PostgreSqlObjectName(reader.GetString("SchemaName"), reader.GetString("TableName")); + var columnName = reader.GetString("ColumnName"); - if (result.TryGetValue(schemaTableName, out var identityColumns)) - { - identityColumns.Add(columnName); - } - else - { - identityColumns = new HashSet() { columnName }; - result.Add(schemaTableName, identityColumns); - } + if (result.TryGetValue(schemaTableName, out var identityColumns)) + { + identityColumns.Add(columnName); + } + else + { + identityColumns = new HashSet() { columnName }; + result.Add(schemaTableName, identityColumns); } - m_SequenceColumns = result.ToImmutableDictionary(x => x.Key, x => x.Value.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)); } + m_SequenceColumns = result.ToImmutableDictionary(x => x.Key, x => x.Value.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)); } } } - return m_SequenceColumns.GetValueOrDefault(tableName, ImmutableHashSet.Empty); } + return m_SequenceColumns.GetValueOrDefault(tableName, ImmutableHashSet.Empty); + } - StoredProcedureMetadata GetStoredProcedureInternal(PostgreSqlObjectName storedProcedureName) + StoredProcedureMetadata GetStoredProcedureInternal(PostgreSqlObjectName storedProcedureName) + { + const string functionSql = @"SELECT routine_schema, routine_name, specific_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND data_type='refcursor' AND routine_schema ILIKE @Schema AND routine_name ILIKE @Name;"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - const string functionSql = @"SELECT routine_schema, routine_name, specific_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND data_type='refcursor' AND routine_schema ILIKE @Schema AND routine_name ILIKE @Name;"; + con.Open(); - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + foreach (var schema in GetSchemasToCheck(storedProcedureName)) { - con.Open(); - - foreach (var schema in GetSchemasToCheck(storedProcedureName)) + string actualSchema; + string actualName; + string specificName; + using (var cmd = new NpgsqlCommand(functionSql, con)) { - string actualSchema; - string actualName; - string specificName; - using (var cmd = new NpgsqlCommand(functionSql, con)) + cmd.Parameters.AddWithValue("@Schema", schema); + cmd.Parameters.AddWithValue("@Name", storedProcedureName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", schema); - cmd.Parameters.AddWithValue("@Name", storedProcedureName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - continue; - actualSchema = reader.GetString("routine_schema"); - actualName = reader.GetString("routine_name"); - specificName = reader.GetString("specific_name"); - } + if (!reader.Read()) + continue; + actualSchema = reader.GetString("routine_schema"); + actualName = reader.GetString("routine_name"); + specificName = reader.GetString("specific_name"); } + } - var pAndC = GetParametersAndColumns(specificName, con); + var pAndC = GetParametersAndColumns(specificName, con); - return new StoredProcedureMetadata(new PostgreSqlObjectName(actualSchema, actualName), pAndC.Item1); - } + return new StoredProcedureMetadata(new PostgreSqlObjectName(actualSchema, actualName), pAndC.Item1); } - - throw new MissingObjectException($"Could not find function {storedProcedureName}"); } - TableFunctionMetadata GetTableFunctionInternal(PostgreSqlObjectName tableFunctionName) + throw new MissingObjectException($"Could not find function {storedProcedureName}"); + } + + TableFunctionMetadata GetTableFunctionInternal(PostgreSqlObjectName tableFunctionName) + { + const string functionSql = @"SELECT routine_schema, routine_name, specific_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND data_type='record' AND routine_schema ILIKE @Schema AND routine_name ILIKE @Name;"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - const string functionSql = @"SELECT routine_schema, routine_name, specific_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND data_type='record' AND routine_schema ILIKE @Schema AND routine_name ILIKE @Name;"; + con.Open(); - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + foreach (var schema in GetSchemasToCheck(tableFunctionName)) { - con.Open(); + string actualSchema; + string actualName; + string specificName; - foreach (var schema in GetSchemasToCheck(tableFunctionName)) + using (var cmd = new NpgsqlCommand(functionSql, con)) { - string actualSchema; - string actualName; - string specificName; - - using (var cmd = new NpgsqlCommand(functionSql, con)) + cmd.Parameters.AddWithValue("@Schema", schema); + cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", schema); - cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - continue; + if (!reader.Read()) + continue; - actualSchema = reader.GetString("routine_schema"); - actualName = reader.GetString("routine_name"); - specificName = reader.GetString("specific_name"); - } + actualSchema = reader.GetString("routine_schema"); + actualName = reader.GetString("routine_name"); + specificName = reader.GetString("specific_name"); } + } - var pAndC = GetParametersAndColumns(specificName, con); + var pAndC = GetParametersAndColumns(specificName, con); - return new TableFunctionMetadata(new PostgreSqlObjectName(actualSchema, actualName), pAndC.Item1, pAndC.Item2); - } + return new TableFunctionMetadata(new PostgreSqlObjectName(actualSchema, actualName), pAndC.Item1, pAndC.Item2); } - - throw new MissingObjectException($"Could not find function {tableFunctionName}"); } - /// - /// Gets the detailed metadata for a table or view. - /// - /// Name of the table. - /// SqlServerTableOrViewMetadata<TDbType>. - public override TableOrViewMetadata GetTableOrView(PostgreSqlObjectName tableName) - { - return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); - } + throw new MissingObjectException($"Could not find function {tableFunctionName}"); + } - /// - /// Gets the detailed metadata for a table or view. - /// - /// Name of the table. - /// Could not find table or view {tableName} - public TableOrViewMetadata GetTableOrViewInternal(PostgreSqlObjectName tableName) + /// + /// Gets the detailed metadata for a table or view. + /// + /// Name of the table. + /// SqlServerTableOrViewMetadata<TDbType>. + public override TableOrViewMetadata GetTableOrView(PostgreSqlObjectName tableName) + { + return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); + } + + /// + /// Gets the detailed metadata for a table or view. + /// + /// Name of the table. + /// Could not find table or view {tableName} + public TableOrViewMetadata GetTableOrViewInternal(PostgreSqlObjectName tableName) + { + const string TableSql = + @"SELECT + table_schema as schemaname, + table_name as tablename, + table_type as type + FROM information_schema.tables + WHERE table_schema ILIKE @Schema AND + table_name ILIKE @Name AND + (table_type='BASE TABLE' OR + table_type='VIEW');"; + + using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) { - const string TableSql = - @"SELECT - table_schema as schemaname, - table_name as tablename, - table_type as type - FROM information_schema.tables - WHERE table_schema ILIKE @Schema AND - table_name ILIKE @Name AND - (table_type='BASE TABLE' OR - table_type='VIEW');"; + con.Open(); - using (var con = new NpgsqlConnection(m_ConnectionBuilder.ConnectionString)) + foreach (var schmea in GetSchemasToCheck(tableName)) { - con.Open(); + string actualSchema; + string actualTableName; + bool isTable; - foreach (var schmea in GetSchemasToCheck(tableName)) + using (var cmd = new NpgsqlCommand(TableSql, con)) { - string actualSchema; - string actualTableName; - bool isTable; - - using (var cmd = new NpgsqlCommand(TableSql, con)) + cmd.Parameters.AddWithValue("@Schema", schmea); + cmd.Parameters.AddWithValue("@Name", tableName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", schmea); - cmd.Parameters.AddWithValue("@Name", tableName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - continue; //try the next schema in the search path - actualSchema = reader.GetString("schemaname"); - actualTableName = reader.GetString("tablename"); - var type = reader.GetString("type"); - isTable = type.Equals("BASE TABLE", StringComparison.Ordinal); - } + if (!reader.Read()) + continue; //try the next schema in the search path + actualSchema = reader.GetString("schemaname"); + actualTableName = reader.GetString("tablename"); + var type = reader.GetString("type"); + isTable = type.Equals("BASE TABLE", StringComparison.Ordinal); } - - var actualName = new PostgreSqlObjectName(actualSchema, actualTableName); - var columns = GetColumns(actualName, con); - return new TableOrViewMetadata(this, actualName, isTable, columns); } - } - throw new MissingObjectException($"Could not find table or view {tableName}"); + var actualName = new PostgreSqlObjectName(actualSchema, actualTableName); + var columns = GetColumns(actualName, con); + return new TableOrViewMetadata(this, actualName, isTable, columns); + } } - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - /// https://stackoverflow.com/a/6582902/5274 - public override int? MaxParameters => 34464; + throw new MissingObjectException($"Could not find table or view {tableName}"); } -} + + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + /// https://stackoverflow.com/a/6582902/5274 + public override int? MaxParameters => 34464; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/Utilities.cs index 5c6dd606f..b0814688a 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSql/Utilities.cs @@ -2,39 +2,50 @@ using NpgsqlTypes; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.PostgreSql +namespace Tortuga.Chain.PostgreSql; + +internal static class Utilities { - internal static class Utilities + /// + /// Gets the parameters from a SQL Builder. + /// + /// The SQL builder. + /// + public static List GetParameters(this SqlBuilder sqlBuilder) { - /// - /// Gets the parameters from a SQL Builder. - /// - /// The SQL builder. - /// - public static List GetParameters(this SqlBuilder sqlBuilder) - { - return sqlBuilder.GetParameters(ParameterBuilderCallback); - } + return sqlBuilder.GetParameters(ParameterBuilderCallback); + } - public static NpgsqlParameter ParameterBuilderCallback(SqlBuilderEntry entry) + public static NpgsqlParameter ParameterBuilderCallback(SqlBuilderEntry entry) + { + var result = new NpgsqlParameter(); + result.ParameterName = entry.Details.SqlVariableName; + result.Value = entry.ParameterValue; + if (entry.Details.DbType.HasValue) + result.NpgsqlDbType = entry.Details.DbType.Value; + return result; + } + + public static bool PrimaryKeyIsIdentity(this SqlBuilder sqlBuilder, out List keyParameters) + { + return sqlBuilder.PrimaryKeyIsIdentity((NpgsqlDbType? type) => { var result = new NpgsqlParameter(); - result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; - if (entry.Details.DbType.HasValue) - result.NpgsqlDbType = entry.Details.DbType.Value; + if (type.HasValue) + result.NpgsqlDbType = type.Value; return result; - } + }, out keyParameters); + } - public static bool PrimaryKeyIsIdentity(this SqlBuilder sqlBuilder, out List keyParameters) + public static bool RequiresSorting(this PostgreSqlLimitOption limitOption) + { + return limitOption switch { - return sqlBuilder.PrimaryKeyIsIdentity((NpgsqlDbType? type) => - { - var result = new NpgsqlParameter(); - if (type.HasValue) - result.NpgsqlDbType = type.Value; - return result; - }, out keyParameters); - } + PostgreSqlLimitOption.None => false, + PostgreSqlLimitOption.Rows => true, + PostgreSqlLimitOption.TableSampleSystemPercentage => false, + PostgreSqlLimitOption.TableSampleBernoulliPercentage => false, + _ => throw new ArgumentOutOfRangeException(nameof(limitOption), limitOption, "Unknown limit option") + }; } } diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlDataSource.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlDataSource.cs index b3ef4676d..42b84b2f1 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlDataSource.cs @@ -3,346 +3,322 @@ using Tortuga.Chain.Core; using Tortuga.Chain.PostgreSql; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class PostgreSqlDataSource. +/// +/// +public partial class PostgreSqlDataSource : PostgreSqlDataSourceBase { + PostgreSqlMetadataCache m_DatabaseMetadata; + /// - /// Class PostgreSqlDataSource. + /// Initializes a new instance of the class. /// - /// - public partial class PostgreSqlDataSource : PostgreSqlDataSourceBase + /// The name. + /// The connection string. + /// The settings. + /// connectionString is null or empty.;connectionString + public PostgreSqlDataSource(string? name, string connectionString, PostgreSqlDataSourceSettings? settings = null) + : base(settings) { - PostgreSqlMetadataCache m_DatabaseMetadata; - - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The connection string. - /// The settings. - /// connectionString is null or empty.;connectionString - public PostgreSqlDataSource(string? name, string connectionString, PostgreSqlDataSourceSettings? settings = null) - : base(settings) - { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); - - m_ConnectionBuilder = new NpgsqlConnectionStringBuilder(connectionString); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.Database; - else - Name = name; + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + + m_ConnectionBuilder = new NpgsqlConnectionStringBuilder(connectionString); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.Database; + else + Name = name; + + m_DatabaseMetadata = new PostgreSqlMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - m_DatabaseMetadata = new PostgreSqlMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + /// + /// Initializes a new instance of the class. + /// + /// The connection string. + /// The settings. + public PostgreSqlDataSource(string connectionString, PostgreSqlDataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The connection string. - /// The settings. - public PostgreSqlDataSource(string connectionString, PostgreSqlDataSourceSettings? settings = null) - : this(null, connectionString, settings) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The connection builder. + /// The settings. + /// + public PostgreSqlDataSource(string? name, NpgsqlConnectionStringBuilder connectionBuilder, PostgreSqlDataSourceSettings? settings = null) + : base(settings) + { + m_ConnectionBuilder = connectionBuilder ?? throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.Database; + else + Name = name; + + m_DatabaseMetadata = new PostgreSqlMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The connection builder. - /// The settings. - /// - public PostgreSqlDataSource(string? name, NpgsqlConnectionStringBuilder connectionBuilder, PostgreSqlDataSourceSettings? settings = null) - : base(settings) - { - m_ConnectionBuilder = connectionBuilder ?? throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.Database; - else - Name = name; + /// + /// Initializes a new instance of the class. + /// + /// The connection builder. + /// The settings. + public PostgreSqlDataSource(NpgsqlConnectionStringBuilder connectionBuilder, PostgreSqlDataSourceSettings? settings = null) + : this(null, connectionBuilder, settings) + { + } - m_DatabaseMetadata = new PostgreSqlMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + PostgreSqlDataSource(string? name, NpgsqlConnectionStringBuilder connectionBuilder, PostgreSqlDataSourceSettings settings, PostgreSqlMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) + : base(settings) + { + m_ConnectionBuilder = connectionBuilder ?? throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.Database; + else + Name = name; + + m_DatabaseMetadata = databaseMetadata; + m_ExtensionCache = extensionCache; + m_Cache = cache; + } - /// - /// Initializes a new instance of the class. - /// - /// The connection builder. - /// The settings. - public PostgreSqlDataSource(NpgsqlConnectionStringBuilder connectionBuilder, PostgreSqlDataSourceSettings? settings = null) - : this(null, connectionBuilder, settings) - { - } + /// + /// Gets the database metadata. + /// + /// The database metadata. + public override PostgreSqlMetadataCache DatabaseMetadata => m_DatabaseMetadata; - PostgreSqlDataSource(string? name, NpgsqlConnectionStringBuilder connectionBuilder, PostgreSqlDataSourceSettings settings, PostgreSqlMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) - : base(settings) + /// + /// Creates a new data source with the indicated changes to the settings. + /// + /// The new settings to use. + /// + /// The new data source will share the same database metadata cache. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public PostgreSqlDataSource WithSettings(PostgreSqlDataSourceSettings? settings) + { + var mergedSettings = new PostgreSqlDataSourceSettings() { - m_ConnectionBuilder = connectionBuilder ?? throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null."); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.Database; - else - Name = name; - - m_DatabaseMetadata = databaseMetadata; - m_ExtensionCache = extensionCache; - m_Cache = cache; - } - - /// - /// Gets the database metadata. - /// - /// The database metadata. - public override PostgreSqlMetadataCache DatabaseMetadata => m_DatabaseMetadata; - - - - + DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, + SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, + StrictMode = settings?.StrictMode ?? StrictMode, + SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode + }; + var result = new PostgreSqlDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); + result.m_DatabaseMetadata = m_DatabaseMetadata; + result.AuditRules = AuditRules; + result.UserValue = UserValue; + + result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); + result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); + result.ExecutionError += (sender, e) => OnExecutionError(e); + result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); + + return result; + } + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// System.Nullable<System.Int32>. + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + try + { + using (var con = CreateConnection()) + { + using (var cmd = new NpgsqlCommand()) + { + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + int? rows; + if (((PostgreSqlCommandExecutionToken)executionToken).DereferenceCursors) + rows = DereferenceCursors(cmd, implementation); + else + rows = implementation(cmd); - /// - /// Creates a new data source with the indicated changes to the settings. - /// - /// The new settings to use. - /// - /// The new data source will share the same database metadata cache. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] - public PostgreSqlDataSource WithSettings(PostgreSqlDataSourceSettings? settings) + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + } + } + catch (Exception ex) { - var mergedSettings = new PostgreSqlDataSourceSettings() - { - DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, - SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, - StrictMode = settings?.StrictMode ?? StrictMode, - SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode - }; - var result = new PostgreSqlDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); - result.m_DatabaseMetadata = m_DatabaseMetadata; - result.AuditRules = AuditRules; - result.UserValue = UserValue; - - result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); - result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); - result.ExecutionError += (sender, e) => OnExecutionError(e); - result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); - - return result; + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// System.Nullable<System.Int32>. - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try - { - using (var con = CreateConnection()) - { - using (var cmd = new NpgsqlCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - int? rows; - - if (((PostgreSqlCommandExecutionToken)executionToken).DereferenceCursors) - rows = DereferenceCursors(cmd, implementation); - else - rows = implementation(cmd); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) + try + { + using (var con = CreateConnection()) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - using (var con = CreateConnection()) + using (var cmd = new NpgsqlCommand()) { - var rows = implementation(con, null); + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + int? rows; + if (((PostgreSqlCommandExecutionToken)executionToken).DereferenceCursors) + rows = await DereferenceCursorsAsync(cmd, implementation).ConfigureAwait(false); + else + rows = await implementation(cmd).ConfigureAwait(false); + + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } } - catch (Exception ex) + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException + { + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; + } + else { OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); throw; } } + } - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try - { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - using (var cmd = new NpgsqlCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - int? rows; - if (((PostgreSqlCommandExecutionToken)executionToken).DereferenceCursors) - rows = await DereferenceCursorsAsync(cmd, implementation).ConfigureAwait(false); - else - rows = await implementation(cmd).ConfigureAwait(false); - - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) + try + { + using (var con = CreateConnection()) { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = CreateConnection()) - { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlExtensions.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlExtensions.cs index af11f2f3e..46b921ec9 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlExtensions.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlExtensions.cs @@ -2,48 +2,47 @@ using System.Collections.Concurrent; using Tortuga.Chain.PostgreSql; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class SqlServerExtensions. +/// +public static class PostgreSqlExtensions { + readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + /// - /// Class SqlServerExtensions. + /// Returns a data source wrapped around the connection. /// - public static class PostgreSqlExtensions + /// The connection. + /// SqlServerOpenDataSource. + /// + public static PostgreSqlOpenDataSource AsDataSource(this NpgsqlConnection connection) { - readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - /// - /// Returns a data source wrapped around the connection. - /// - /// The connection. - /// SqlServerOpenDataSource. - /// - public static PostgreSqlOpenDataSource AsDataSource(this NpgsqlConnection connection) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); - - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new PostgreSqlDataSource(cs)); - return new PostgreSqlOpenDataSource(dataSourceBase, connection, null); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new PostgreSqlDataSource(cs)); + return new PostgreSqlOpenDataSource(dataSourceBase, connection, null); + } - /// - /// Returns a data source wrapped around the transaction. - /// - /// The connection. - /// The transaction. - /// SqlServerOpenDataSource. - /// - public static PostgreSqlOpenDataSource AsDataSource(this NpgsqlConnection connection, NpgsqlTransaction transaction) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); + /// + /// Returns a data source wrapped around the transaction. + /// + /// The connection. + /// The transaction. + /// SqlServerOpenDataSource. + /// + public static PostgreSqlOpenDataSource AsDataSource(this NpgsqlConnection connection, NpgsqlTransaction transaction) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new PostgreSqlDataSource(cs)); - return new PostgreSqlOpenDataSource(dataSourceBase, connection, transaction); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new PostgreSqlDataSource(cs)); + return new PostgreSqlOpenDataSource(dataSourceBase, connection, transaction); } } diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlLimitOption.cs b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlLimitOption.cs index 84efdeaa6..0e01d8749 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlLimitOption.cs +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/PostgreSqlLimitOption.cs @@ -1,29 +1,28 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Limit options supported by PostgreSQL. +/// +/// This is a strict subset of LimitOptions +public enum PostgreSqlLimitOption { /// - /// Limit options supported by PostgreSQL. + /// No limits were applied. /// - /// This is a strict subset of LimitOptions - public enum PostgreSqlLimitOption - { - /// - /// No limits were applied. - /// - None = LimitOptions.None, + None = LimitOptions.None, - /// - /// Returns the indicated number of rows with optional offset - /// - Rows = LimitOptions.Rows, + /// + /// Returns the indicated number of rows with optional offset + /// + Rows = LimitOptions.Rows, - /// - /// Randomly sample N percentage of rows using the Table Sample System algorithm. - /// - TableSampleSystemPercentage = LimitOptions.TableSampleSystemPercentage, + /// + /// Randomly sample N percentage of rows using the Table Sample System algorithm. + /// + TableSampleSystemPercentage = LimitOptions.TableSampleSystemPercentage, - /// - /// Randomly sample N percentage of rows using the Table Sample Bernoulli algorithm. - /// - TableSampleBernoulliPercentage = LimitOptions.TableSampleBernoulliPercentage, - } + /// + /// Randomly sample N percentage of rows using the Table Sample Bernoulli algorithm. + /// + TableSampleBernoulliPercentage = LimitOptions.TableSampleBernoulliPercentage, } diff --git a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Tortuga.Chain.PostgreSql.csproj b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Tortuga.Chain.PostgreSql.csproj index cb7a55700..3be2999ab 100644 --- a/Tortuga.Chain/Tortuga.Chain.PostgreSql/Tortuga.Chain.PostgreSql.csproj +++ b/Tortuga.Chain/Tortuga.Chain.PostgreSql/Tortuga.Chain.PostgreSql.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -56,7 +56,7 @@ - + @@ -76,7 +76,7 @@ - true + Generated @@ -84,7 +84,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite.Tests/Setup.cs b/Tortuga.Chain/Tortuga.Chain.SQLite.Tests/Setup.cs index 6c8ef9422..9e3fbb8cf 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite.Tests/Setup.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite.Tests/Setup.cs @@ -70,10 +70,11 @@ State Char(2) NOT NULL, DeletedFlag BIT NOT NULL Default 0, DeletedDate DateTimeOffset NULL, - DeletedByKey INTEGER NULL + DeletedByKey INTEGER NULL, + BirthDay DATE NULL, + PreferredCallTime TIME )"; - string sql3 = @"CREATE TABLE Location ( LocationKey INTEGER PRIMARY KEY, @@ -137,4 +138,4 @@ FROM Employee e } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index d2e3ee4e0..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,28 +0,0 @@ -/* -Container class: Tortuga.Chain.SQLiteDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.SQLite.SQLiteDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsTruncateTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsInsertBatchTrait> - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait - Adding trait: Traits.SupportsUpsertTrait -Container class: Tortuga.Chain.SQLite.SQLiteOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.SQLite.SQLiteTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteDataSourceBase.cs deleted file mode 100644 index f4b0932a9..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteDataSourceBase.cs +++ /dev/null @@ -1,1148 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SQLite -{ - partial class SQLiteDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsTruncate, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsInsertBatch, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Tortuga.Chain.DataSources.ISupportsUpsert, Traits.ICommandHelper, Traits.IInsertBatchHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper, Traits.IUpsertHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsTruncateTrait ___Trait1 = new(); - private Traits.SupportsTruncateTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait2 = new(); - private Traits.SupportsSqlQueriesTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsInsertBatchTrait> ___Trait3 = new(); - private Traits.SupportsInsertBatchTrait> __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait4 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsUpdateTrait ___Trait5 = new(); - private Traits.SupportsUpdateTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsDeleteTrait ___Trait6 = new(); - private Traits.SupportsDeleteTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait7 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsInsertTrait ___Trait8 = new(); - private Traits.SupportsInsertTrait __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsUpdateSet ___Trait9 = new(); - private Traits.SupportsUpdateSet __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsDeleteSet ___Trait10 = new(); - private Traits.SupportsDeleteSet __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - private Traits.SupportsFromTrait ___Trait11 = new(); - private Traits.SupportsFromTrait __Trait11 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait11; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait12 = new(); - private Traits.SupportsGetByKeyListTrait __Trait12 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait12; - } - } - private Traits.SupportsUpsertTrait ___Trait13 = new(); - private Traits.SupportsUpsertTrait __Trait13 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait13; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait6).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait6).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait4).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBatch - Tortuga.Chain.CommandBuilders.IDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertBatch(objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.String tableName, System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(tableName, objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(objects, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait2).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTruncate - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate() - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait7).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, newValues, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(argumentValue, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.SQLite.SQLiteObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SQLite.SQLiteObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait10.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait10.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait10.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait10.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait6.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait6.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SQLite.SQLiteObjectName tableOrViewName) - { - return __Trait11.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SQLite.SQLiteObjectName tableOrViewName, System.String whereClause) - { - return __Trait11.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SQLite.SQLiteObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait11.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SQLite.SQLiteObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait11.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait11.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait11.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait11.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait11.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.String key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TKey key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertBatchTrait> - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// Name of the table. - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.DbCommandBuilder InsertBatch(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.DbCommandBuilder InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(objects, options); - } - - /// - /// Performs a series of batch inserts. - /// - /// The type of the t object. - /// Name of the table. - /// The objects. - /// The options. - /// Tortuga.Chain.ILink<System.Int32>. - /// This operation is not atomic. It should be wrapped in a transaction. - public Tortuga.Chain.ILink InsertMultipleBatch(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.ILink InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(objects, options); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait2.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait2.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsTruncateTrait - - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate(Tortuga.Chain.SQLite.SQLiteObjectName tableName) - { - return __Trait1.Truncate(tableName); - } - - /// Truncates the specified table. - /// This class used to determine which table to Truncate - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate()where TObject : class - { - return __Trait1.Truncate(); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SQLite.SQLiteObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsUpsertTrait - - /// - /// Creates a operation used to perform an "upsert" operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(Tortuga.Chain.SQLite.SQLiteObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(tableName, argumentValue, options); - } - - /// - /// Perform an insert or update operation as appropriate. - /// - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.SQLite.SQLiteObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private partial Tortuga.Chain.ILink OnTruncate(Tortuga.Chain.SQLite.SQLiteObjectName tableName ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.OnTruncate = OnTruncate; - __Trait1.DataSource = this; - __Trait2.OnSql = OnSql; - __Trait3.DataSource = this; - __Trait4.DataSource = this; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - __Trait11.DataSource = this; - __Trait12.DataSource = this; - __Trait13.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteOpenDataSource.cs deleted file mode 100644 index a74140936..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SQLite -{ - partial class SQLiteOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.SQLite.SQLiteConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.SQLite.SQLiteTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SQLite.SQLiteMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.SQLiteDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.SQLite.SQLiteConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Data.SQLite.SQLiteTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SQLite.SQLiteOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SQLite.SQLiteOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SQLite.SQLiteOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SQLite.SQLiteOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteTransactionalDataSource.cs deleted file mode 100644 index dbc38c241..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLite.SQLiteTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SQLite -{ - partial class SQLiteTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.SQLite.SQLiteConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.SQLite.SQLiteTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SQLite.SQLiteMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.SQLiteDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.SQLite.SQLiteConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private System.Data.SQLite.SQLiteTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLiteDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLiteDataSource.cs deleted file mode 100644 index ad8506fb5..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SQLiteDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class SQLiteDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SQLite.SQLiteTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SQLite.SQLiteTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public System.Data.SQLite.SQLiteConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SQLite.SQLiteOpenDataSource CreateOpenDataSource(System.Data.SQLite.SQLiteConnection connection, System.Data.SQLite.SQLiteTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SQLite.SQLiteOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private System.Data.SQLite.SQLiteConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.SQLiteDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SQLiteDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SQLiteDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SQLiteDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SQLite.SQLiteTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SQLiteDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial System.Data.SQLite.SQLiteConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SQLite.SQLiteOpenDataSource OnCreateOpenDataSource(System.Data.SQLite.SQLiteConnection connection, System.Data.SQLite.SQLiteTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteObject.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteObject.cs index 86816ba22..e186e7b03 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteObject.cs @@ -52,4 +52,4 @@ public override CommandExecutionToken Prepare(Ma return new SQLiteCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(), lockType: LockType.Write).CheckDeleteRowCount(m_Options); } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteSet.cs index b5db43a4c..b01b87d87 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteDeleteSet.cs @@ -14,6 +14,7 @@ internal sealed class SQLiteDeleteSet : MultipleRowDbCommandBuilder m_Table; readonly string? m_WhereClause; - readonly int? m_ExpectedRowCount; /// /// Initializes a new instance of the class. @@ -143,4 +143,4 @@ public override CommandExecutionToken Prepare(Ma /// public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertBatch`1.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertBatch`1.cs index 229bc786c..53c0ed783 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertBatch`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertBatch`1.cs @@ -96,4 +96,4 @@ public override CommandExecutionToken Prepare(Ma /// public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertObject.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertObject.cs index bdfaa7257..4caf127a0 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertObject.cs @@ -53,4 +53,4 @@ public override CommandExecutionToken Prepare(Ma return new SQLiteCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(), lockType: LockType.Write); } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertOrUpdateObject.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertOrUpdateObject.cs index 73a016e88..340628006 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertOrUpdateObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteInsertOrUpdateObject.cs @@ -66,4 +66,4 @@ public override CommandExecutionToken Prepare(Ma return new SQLiteCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(), lockType: LockType.Write); } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteObjectCommand.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteObjectCommand.cs index 14e43dcaa..cd9802c50 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteObjectCommand.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteObjectCommand.cs @@ -33,4 +33,4 @@ protected SQLiteObjectCommand(SQLiteDataSourceBase dataSource, SQLiteObjectName /// protected override TableOrViewMetadata OnGetTable() => Table; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteTableOrView.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteTableOrView.cs index ddd6e9150..57e26d08b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteTableOrView.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteTableOrView.cs @@ -144,7 +144,18 @@ public override CommandExecutionToken Prepare(Ma sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); parameters = sqlBuilder.GetParameters(); } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any()) + { + if (m_Table.HasPrimaryKey) + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_Table.PrimaryKeyColumns.Select(x => new SortExpression(x.SqlName)), null); + else if (StrictMode) + throw new InvalidOperationException("Limits were requested, but no primary keys were detected. Use WithSorting to supply a sort order or disable strict mode."); + } + else + { + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + } switch (m_LimitOptions) { @@ -219,20 +230,6 @@ protected override TableDbCommandBuilder - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); - - m_SortExpressions = sortExpressions; - return this; - } - /// /// Adds limits to the command builder. /// @@ -266,5 +263,19 @@ protected override TableDbCommandBuilder + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; + } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateObject.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateObject.cs index 5248e8048..9a5c25865 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateObject.cs @@ -63,4 +63,4 @@ public override CommandExecutionToken Prepare(Ma return new SQLiteCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters(), lockType: LockType.Write).CheckUpdateRowCount(m_Options); } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateSet.cs index 94b388fd9..8749fa1e7 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/CommandBuilders/SQLiteUpdateSet.cs @@ -240,4 +240,4 @@ public override UpdateSetDbCommandBuilder WithFi return this; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteDataSourceBase.Traits.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteDataSourceBase.Traits.cs index 8bbe18e60..2a33a0cea 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteDataSourceBase.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteDataSourceBase.Traits.cs @@ -9,8 +9,8 @@ namespace Tortuga.Chain.SQLite; -[UseTrait(typeof(SupportsDeleteAllTrait))] -[UseTrait(typeof(SupportsTruncateTrait))] +[UseTrait(typeof(SupportsDeleteAllTrait))] +[UseTrait(typeof(SupportsTruncateTrait))] [UseTrait(typeof(SupportsSqlQueriesTrait))] [UseTrait(typeof(SupportsInsertBatchTrait>))] @@ -24,6 +24,7 @@ namespace Tortuga.Chain.SQLite; [UseTrait(typeof(SupportsFromTrait))] [UseTrait(typeof(SupportsGetByKeyListTrait))] [UseTrait(typeof(SupportsUpsertTrait))] +[UseTrait(typeof(SupportsGetByColumnListTrait))] partial class SQLiteDataSourceBase : ICrudDataSource, IAdvancedCrudDataSource { DatabaseMetadataCache ICommandHelper.DatabaseMetadata => DatabaseMetadata; @@ -96,10 +97,9 @@ TableDbCommandBuilder(this, tableOrViewName, filterValue, filterOptions); } - SingleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class { - string where = keyColumn.SqlName + " = @Param0"; var parameters = new List(); @@ -131,7 +131,6 @@ MultipleRowDbCommandBuilder IGetByKeyHelper< } return new MultipleRowDbCommandBuilder(new SQLiteTableOrView(this, tableName, where, parameters)); - } DbCommandBuilder IInsertBatchHelper.OnInsertBatch(AbstractObjectName tableName, IEnumerable objects, InsertOptions options) @@ -145,9 +144,13 @@ ObjectDbCommandBuilder IInsertHel return new SQLiteInsertObject(this, tableName, argumentValue, options); } - MultipleRowDbCommandBuilder IUpdateDeleteByKeyHelper.OnUpdateByKeyList(AbstractObjectName tableName, TArgument newValues, IEnumerable keys, UpdateOptions options) + ObjectDbCommandBuilder IUpsertHelper.OnInsertOrUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpsertOptions options) { + return new SQLiteInsertOrUpdateObject(this, tableName, argumentValue, options); + } + MultipleRowDbCommandBuilder IUpdateDeleteByKeyHelper.OnUpdateByKeyList(AbstractObjectName tableName, TArgument newValues, IEnumerable keys, UpdateOptions options) + { var primaryKeys = DatabaseMetadata.GetTableOrView(tableName).PrimaryKeyColumns; if (primaryKeys.Count != 1) throw new MappingException($"{nameof(UpdateByKeyList)} operation isn't allowed on {tableName} because it doesn't have a single primary key."); @@ -206,11 +209,4 @@ private partial MultipleTableDbCommandBuilder IUpsertHelper.OnInsertOrUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpsertOptions options) - { - return new SQLiteInsertOrUpdateObject(this, tableName, argumentValue, options); - } } - - diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteMetadataCache.cs index d4932ecb7..65b82a124 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteMetadataCache.cs @@ -12,9 +12,9 @@ namespace Tortuga.Chain.SQLite public sealed class SQLiteMetadataCache : DbDatabaseMetadataCache { readonly SQLiteConnectionStringBuilder m_ConnectionBuilder; - readonly ConcurrentDictionary> m_Tables = new ConcurrentDictionary>(); + readonly ConcurrentDictionary> m_Tables = new(); - readonly ConcurrentDictionary> m_TypeTableMap = new ConcurrentDictionary>(); + readonly ConcurrentDictionary> m_TypeTableMap = new(); /// /// Creates a new instance of @@ -25,6 +25,13 @@ public SQLiteMetadataCache(SQLiteConnectionStringBuilder connectionBuilder) m_ConnectionBuilder = connectionBuilder; } + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + /// https://sqlite.org/limits.html + public override int? MaxParameters => 999; + /// /// Gets the indexes for a table. /// @@ -138,9 +145,9 @@ public void PreloadTables() { const string tableSql = @"SELECT - tbl_name as TableName - FROM sqlite_master - WHERE type = 'table'"; + tbl_name as TableName + FROM sqlite_master + WHERE type = 'table'"; using (var con = new SQLiteConnection(m_ConnectionBuilder.ConnectionString)) { @@ -167,9 +174,9 @@ public void PreloadViews() { const string viewSql = @"SELECT - tbl_name as ViewName - FROM sqlite_master - WHERE type = 'view'"; + tbl_name as ViewName + FROM sqlite_master + WHERE type = 'view'"; using (var con = new SQLiteConnection(m_ConnectionBuilder.ConnectionString)) { @@ -250,6 +257,7 @@ public override void Reset() case "REAL": return DbType.Single; case "SMALLINT": return DbType.Int16; case "TEXT": return DbType.AnsiString; + case "TIME": return DbType.Time; case "TINYINT": return DbType.SByte; case "UNSIGNED BIG INT": return DbType.UInt64; case "VARCHAR": return DbType.AnsiString; @@ -262,8 +270,8 @@ public override void Reset() ColumnMetadataCollection GetColumns(SQLiteObjectName tableName, bool isTable) { /* NOTE: Should be safe since GetTableOrViewInternal returns null after querying the table name with a - ** prepared statement, thus proving that the table name exists. - */ + ** prepared statement, thus proving that the table name exists. + */ var hasPrimarykey = false; var columnSql = $"PRAGMA table_info('{tableName.Name}')"; @@ -301,11 +309,11 @@ private TableOrViewMetadata GetTableOrViewInternal(SQL { const string tableSql = @"SELECT - type AS ObjectType, - tbl_name AS ObjectName - FROM sqlite_master - WHERE UPPER(tbl_name) = UPPER(@Name) AND - (type='table' OR type='view')"; + type AS ObjectType, + tbl_name AS ObjectName + FROM sqlite_master + WHERE UPPER(tbl_name) = UPPER(@Name) AND + (type='table' OR type='view')"; string actualName; bool isTable; @@ -331,12 +339,5 @@ WHERE UPPER(tbl_name) = UPPER(@Name) AND var columns = GetColumns(tableName, isTable); return new TableOrViewMetadata(this, actualName, isTable, columns); } - - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - /// https://sqlite.org/limits.html - public override int? MaxParameters => 999; } } diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteOpenDataSource.cs index addd224c7..d1d6f94ac 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteOpenDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteOpenDataSource.cs @@ -14,7 +14,6 @@ namespace Tortuga.Chain.SQLite [UseTrait(typeof(OpenDataSourceTrait))] public partial class SQLiteOpenDataSource : SQLiteDataSourceBase { - internal SQLiteOpenDataSource(SQLiteDataSource dataSource, SQLiteConnection connection, SQLiteTransaction? transaction) : base(new SQLiteDataSourceSettings(dataSource)) { if (connection == null) @@ -67,14 +66,7 @@ internal override AsyncReaderWriterLock SyncLock cmd.Connection = m_Connection; if (m_Transaction != null) cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); var rows = implementation(cmd); executionToken.RaiseCommandExecuted(cmd, rows); @@ -173,14 +165,7 @@ internal override AsyncReaderWriterLock SyncLock cmd.Connection = m_Connection; if (m_Transaction != null) cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); var rows = await implementation(cmd).ConfigureAwait(false); executionToken.RaiseCommandExecuted(cmd, rows); @@ -273,4 +258,4 @@ private partial SQLiteOpenDataSource OnOverride(IEnumerable? addition return this; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteTransactionalDataSource.cs index c9fbd822f..f9497412a 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteTransactionalDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/SQLiteTransactionalDataSource.cs @@ -14,7 +14,6 @@ namespace Tortuga.Chain.SQLite [UseTrait(typeof(TransactionalDataSourceTrait))] public partial class SQLiteTransactionalDataSource : SQLiteDataSourceBase, IHasOnDispose { - [SuppressMessage("Microsoft.Usage", "CA2213")] private IDisposable m_LockToken; @@ -93,13 +92,17 @@ internal SQLiteTransactionalDataSource(SQLiteDataSource dataSource, bool forward UserValue = dataSource.UserValue; } - - internal override AsyncReaderWriterLock SyncLock { get { return m_BaseDataSource.SyncLock; } } + void IHasOnDispose.OnDispose() + { + if (m_LockToken != null) + m_LockToken.Dispose(); + } + /// /// Executes the specified execution token. /// @@ -128,14 +131,7 @@ internal override AsyncReaderWriterLock SyncLock { cmd.Connection = m_Connection; cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); var rows = implementation(cmd); executionToken.RaiseCommandExecuted(cmd, rows); @@ -211,14 +207,7 @@ internal override AsyncReaderWriterLock SyncLock { cmd.Connection = m_Connection; cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); var rows = await implementation(cmd).ConfigureAwait(false); executionToken.RaiseCommandExecuted(cmd, rows); @@ -283,11 +272,5 @@ internal override AsyncReaderWriterLock SyncLock } } } - - void IHasOnDispose.OnDispose() - { - if (m_LockToken != null) - m_LockToken.Dispose(); - } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/Utilities.cs index fc15af674..8233f11d8 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLite/Utilities.cs @@ -5,26 +5,48 @@ namespace Tortuga.Chain.SQLite { internal static class Utilities { - /// - /// Gets the parameters from a SQL Builder. - /// - /// The SQL builder. - /// - public static List GetParameters(this SqlBuilder sqlBuilder) + public static List GetParameters(this SqlBuilder sqlBuilder) { return sqlBuilder.GetParameters(ParameterBuilderCallback); } + /// + /// Callback for parameter builder. + /// + /// The entry. + /// SqlDbType. public static SQLiteParameter ParameterBuilderCallback(SqlBuilderEntry entry) { var result = new SQLiteParameter(); result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; + + result.Value = entry.ParameterValue switch + { +#if NET6_0_OR_GREATER + DateOnly dateOnly => dateOnly.ToDateTime(default), + TimeOnly timeOnly => default(DateTime) + timeOnly.ToTimeSpan(), +#endif + TimeSpan timeSpan => default(DateTime) + timeSpan, + _ => entry.ParameterValue + }; if (entry.Details.DbType.HasValue) result.DbType = entry.Details.DbType.Value; + result.Direction = entry.Details.Direction; + return result; } + + public static bool RequiresSorting(this SQLiteLimitOption limitOption) + { + return limitOption switch + { + SQLiteLimitOption.None => false, + SQLiteLimitOption.Rows => true, + SQLiteLimitOption.RandomSampleRows => false, + _ => throw new ArgumentOutOfRangeException(nameof(limitOption), limitOption, "Unknown limit option") + }; + } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteDataSource.cs index 0080cb0ac..b5275cd04 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteDataSource.cs @@ -5,389 +5,372 @@ using Tortuga.Chain.Core; using Tortuga.Chain.SQLite; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class that represents a SQLite Data Source. +/// +public partial class SQLiteDataSource : SQLiteDataSourceBase { + readonly AsyncReaderWriterLock m_SyncLock = new AsyncReaderWriterLock(); //Sqlite is single-threaded for writes. It says otherwise, but it spams the trace window with exceptions. + SQLiteMetadataCache m_DatabaseMetadata; + /// - /// Class that represents a SQLite Data Source. + /// Initializes a new instance of the class. /// - public partial class SQLiteDataSource : SQLiteDataSourceBase + /// The name of the data source. + /// The connection string. + /// Optional settings object. + /// Connection string is null or empty.;connectionString + public SQLiteDataSource(string? name, string connectionString, SQLiteDataSourceSettings? settings = null) : base(settings) { - readonly AsyncReaderWriterLock m_SyncLock = new AsyncReaderWriterLock(); //Sqlite is single-threaded for writes. It says otherwise, but it spams the trace window with exceptions. - SQLiteMetadataCache m_DatabaseMetadata; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the data source. - /// The connection string. - /// Optional settings object. - /// Connection string is null or empty.;connectionString - public SQLiteDataSource(string? name, string connectionString, SQLiteDataSourceSettings? settings = null) : base(settings) - { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException("Connection string is null or empty.", nameof(connectionString)); + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException("Connection string is null or empty.", nameof(connectionString)); - m_ConnectionBuilder = new SQLiteConnectionStringBuilder(connectionString); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + m_ConnectionBuilder = new SQLiteConnectionStringBuilder(connectionString); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; - m_DatabaseMetadata = new SQLiteMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; + m_DatabaseMetadata = new SQLiteMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; - if (settings != null) - EnforceForeignKeys = settings.EnforceForeignKeys; - } + if (settings != null) + EnforceForeignKeys = settings.EnforceForeignKeys; + } - /// - /// Initializes a new instance of the class. - /// - /// - /// Optional settings object. - public SQLiteDataSource(string connectionString, SQLiteDataSourceSettings? settings = null) - : this(null, connectionString, settings) - { - } + /// + /// Initializes a new instance of the class. + /// + /// + /// Optional settings object. + public SQLiteDataSource(string connectionString, SQLiteDataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - /// - /// Initializes a new instance of the class. - /// - /// The name of the data source. - /// The connection string builder. - /// Optional settings object. - /// connectionStringBuilder;connectionStringBuilder is null. - public SQLiteDataSource(string? name, SQLiteConnectionStringBuilder connectionStringBuilder, SQLiteDataSourceSettings? settings = null) : base(settings) - { - if (connectionStringBuilder == null) - throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + /// + /// Initializes a new instance of the class. + /// + /// The name of the data source. + /// The connection string builder. + /// Optional settings object. + /// connectionStringBuilder;connectionStringBuilder is null. + public SQLiteDataSource(string? name, SQLiteConnectionStringBuilder connectionStringBuilder, SQLiteDataSourceSettings? settings = null) : base(settings) + { + if (connectionStringBuilder == null) + throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + + m_ConnectionBuilder = connectionStringBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; + + m_DatabaseMetadata = new SQLiteMetadataCache(m_ConnectionBuilder); + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - m_ConnectionBuilder = connectionStringBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + /// + /// Initializes a new instance of the class. + /// + /// + /// Optional settings object. + public SQLiteDataSource(SQLiteConnectionStringBuilder connectionStringBuilder, SQLiteDataSourceSettings? settings = null) + : this(null, connectionStringBuilder, settings) + { + } - m_DatabaseMetadata = new SQLiteMetadataCache(m_ConnectionBuilder); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + SQLiteDataSource(string? name, SQLiteConnectionStringBuilder connectionStringBuilder, SQLiteDataSourceSettings settings, SQLiteMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + { + if (connectionStringBuilder == null) + throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); - /// - /// Initializes a new instance of the class. - /// - /// - /// Optional settings object. - public SQLiteDataSource(SQLiteConnectionStringBuilder connectionStringBuilder, SQLiteDataSourceSettings? settings = null) - : this(null, connectionStringBuilder, settings) - { - } + m_ConnectionBuilder = connectionStringBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; - SQLiteDataSource(string? name, SQLiteConnectionStringBuilder connectionStringBuilder, SQLiteDataSourceSettings settings, SQLiteMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) - { - if (connectionStringBuilder == null) - throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + m_DatabaseMetadata = databaseMetadata; + m_ExtensionCache = extensionCache; + m_Cache = cache; - m_ConnectionBuilder = connectionStringBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + if (settings != null) + EnforceForeignKeys = settings.EnforceForeignKeys; + } - m_DatabaseMetadata = databaseMetadata; - m_ExtensionCache = extensionCache; - m_Cache = cache; + /// + /// This object can be used to lookup database information. + /// + public override SQLiteMetadataCache DatabaseMetadata + { + get { return m_DatabaseMetadata; } + } - if (settings != null) - EnforceForeignKeys = settings.EnforceForeignKeys; - } + /// + /// If set, foreign keys will be enabled/disabled as per 'PRAGMA foreign_keys = ON|OFF'. When null, SQLite's default is used. + /// + /// Currently the SQLite default is off, but this may change in a future version. The SQLite documentation recommends always explicitly setting this value. + public bool? EnforceForeignKeys { get; } - /// - /// This object can be used to lookup database information. - /// - public override SQLiteMetadataCache DatabaseMetadata + internal override AsyncReaderWriterLock SyncLock + { + get { return m_SyncLock; } + } + + /// + /// Creates a new data source with the indicated changes to the settings. + /// + /// The new settings to use. + /// + /// The new data source will share the same database metadata cache. + public SQLiteDataSource WithSettings(SQLiteDataSourceSettings? settings) + { + var mergedSettings = new SQLiteDataSourceSettings() { - get { return m_DatabaseMetadata; } - } + DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, + SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, + StrictMode = settings?.StrictMode ?? StrictMode, + SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode, + DisableLocks = settings?.DisableLocks ?? DisableLocks, + EnforceForeignKeys = settings?.EnforceForeignKeys ?? EnforceForeignKeys + }; + var result = new SQLiteDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); + result.m_DatabaseMetadata = m_DatabaseMetadata; + result.AuditRules = AuditRules; + result.UserValue = UserValue; + + result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); + result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); + result.ExecutionError += (sender, e) => OnExecutionError(e); + result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); + + return result; + } - /// - /// If set, foreign keys will be enabled/disabled as per 'PRAGMA foreign_keys = ON|OFF'. When null, SQLite's default is used. - /// - /// Currently the SQLite default is off, but this may change in a future version. The SQLite documentation recommends always explicitly setting this value. - public bool? EnforceForeignKeys { get; } + /// + /// Executes the specified operation. + /// + /// + /// + /// + [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - internal override AsyncReaderWriterLock SyncLock - { - get { return m_SyncLock; } - } + var mode = DisableLocks ? LockType.None : (executionToken as SQLiteCommandExecutionToken)?.LockType ?? LockType.Write; + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Creates a new data source with the indicated changes to the settings. - /// - /// The new settings to use. - /// - /// The new data source will share the same database metadata cache. - public SQLiteDataSource WithSettings(SQLiteDataSourceSettings? settings) + IDisposable? lockToken = null; + try { - var mergedSettings = new SQLiteDataSourceSettings() + switch (mode) { - DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, - SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, - StrictMode = settings?.StrictMode ?? StrictMode, - SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode, - DisableLocks = settings?.DisableLocks ?? DisableLocks, - EnforceForeignKeys = settings?.EnforceForeignKeys ?? EnforceForeignKeys - }; - var result = new SQLiteDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); - result.m_DatabaseMetadata = m_DatabaseMetadata; - result.AuditRules = AuditRules; - result.UserValue = UserValue; - - result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); - result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); - result.ExecutionError += (sender, e) => OnExecutionError(e); - result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); - - return result; - } - - /// - /// Executes the specified operation. - /// - /// - /// - /// - [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var mode = DisableLocks ? LockType.None : (executionToken as SQLiteCommandExecutionToken)?.LockType ?? LockType.Write; - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + case LockType.Read: lockToken = SyncLock.ReaderLock(); break; + case LockType.Write: lockToken = SyncLock.WriterLock(); break; + } - IDisposable? lockToken = null; - try + using (var con = CreateConnection()) { - switch (mode) + using (var cmd = new SQLiteCommand()) { - case LockType.Read: lockToken = SyncLock.ReaderLock(); break; - case LockType.Write: lockToken = SyncLock.WriterLock(); break; - } + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); - using (var con = CreateConnection()) - { - using (var cmd = new SQLiteCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - //TODO: add potential check for this type. - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } - finally - { - if (lockToken != null) - lockToken.Dispose(); - } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - /// System.Nullable<System.Int32>. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + finally { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + if (lockToken != null) + lockToken.Dispose(); + } + } - var mode = DisableLocks ? LockType.None : (executionToken as SQLiteOperationExecutionToken)?.LockType ?? LockType.Write; + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + /// System.Nullable<System.Int32>. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var mode = DisableLocks ? LockType.None : (executionToken as SQLiteOperationExecutionToken)?.LockType ?? LockType.Write; - IDisposable? lockToken = null; - try - { - switch (mode) - { - case LockType.Read: lockToken = SyncLock.ReaderLock(); break; - case LockType.Write: lockToken = SyncLock.WriterLock(); break; - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - using (var con = CreateConnection()) - { - var rows = implementation(con, null); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) + IDisposable? lockToken = null; + try + { + switch (mode) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + case LockType.Read: lockToken = SyncLock.ReaderLock(); break; + case LockType.Write: lockToken = SyncLock.WriterLock(); break; } - finally + + using (var con = CreateConnection()) { - if (lockToken != null) - lockToken.Dispose(); + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Executes the specified operation asynchronously. - /// - /// - /// - /// - /// - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + finally + { + if (lockToken != null) + lockToken.Dispose(); + } + } - var mode = DisableLocks ? LockType.None : (executionToken as SQLiteCommandExecutionToken)?.LockType ?? LockType.Write; + /// + /// Executes the specified operation asynchronously. + /// + /// + /// + /// + /// + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var mode = DisableLocks ? LockType.None : (executionToken as SQLiteCommandExecutionToken)?.LockType ?? LockType.Write; - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - IDisposable? lockToken = null; - try + IDisposable? lockToken = null; + try + { + switch (mode) { - switch (mode) - { - case LockType.Read: lockToken = await SyncLock.ReaderLockAsync().ConfigureAwait(false); break; - case LockType.Write: lockToken = await SyncLock.WriterLockAsync().ConfigureAwait(false); break; - } + case LockType.Read: lockToken = await SyncLock.ReaderLockAsync().ConfigureAwait(false); break; + case LockType.Write: lockToken = await SyncLock.WriterLockAsync().ConfigureAwait(false); break; + } - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) + { + using (var cmd = new SQLiteCommand()) { - using (var cmd = new SQLiteCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - catch (Exception ex) + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert SQLiteException into a OperationCanceledException { - if (cancellationToken.IsCancellationRequested) //convert SQLiteException into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; } - finally + else { - if (lockToken != null) - lockToken.Dispose(); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + finally { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + if (lockToken != null) + lockToken.Dispose(); + } + } + + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var mode = DisableLocks ? LockType.None : (executionToken as SQLiteOperationExecutionToken)?.LockType ?? LockType.Write; + var mode = DisableLocks ? LockType.None : (executionToken as SQLiteOperationExecutionToken)?.LockType ?? LockType.Write; - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - IDisposable? lockToken = null; - try + IDisposable? lockToken = null; + try + { + switch (mode) { - switch (mode) - { - case LockType.Read: lockToken = await SyncLock.ReaderLockAsync().ConfigureAwait(false); break; - case LockType.Write: lockToken = await SyncLock.WriterLockAsync().ConfigureAwait(false); break; - } + case LockType.Read: lockToken = await SyncLock.ReaderLockAsync().ConfigureAwait(false); break; + case LockType.Write: lockToken = await SyncLock.WriterLockAsync().ConfigureAwait(false); break; + } - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) + { + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } - catch (Exception ex) + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert SQLiteException into a OperationCanceledException { - if (cancellationToken.IsCancellationRequested) //convert SQLiteException into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex2, state); + throw ex2; } - finally + else { - if (lockToken != null) - lockToken.Dispose(); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + finally + { + if (lockToken != null) + lockToken.Dispose(); + } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteExtensions.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteExtensions.cs index e7077448d..cda1946f9 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteExtensions.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteExtensions.cs @@ -2,48 +2,47 @@ using System.Data.SQLite; using Tortuga.Chain.SQLite; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class SqlServerExtensions. +/// +public static class SQLiteExtensions { + readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + /// - /// Class SqlServerExtensions. + /// Returns a data source wrapped around the connection. /// - public static class SQLiteExtensions + /// The connection. + /// SqlServerOpenDataSource. + /// + public static SQLiteOpenDataSource AsDataSource(this SQLiteConnection connection) { - readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - /// - /// Returns a data source wrapped around the connection. - /// - /// The connection. - /// SqlServerOpenDataSource. - /// - public static SQLiteOpenDataSource AsDataSource(this SQLiteConnection connection) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); - - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SQLiteDataSource(cs)); - return new SQLiteOpenDataSource(dataSourceBase, connection, null); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SQLiteDataSource(cs)); + return new SQLiteOpenDataSource(dataSourceBase, connection, null); + } - /// - /// Returns a data source wrapped around the transaction. - /// - /// The connection. - /// The transaction. - /// SqlServerOpenDataSource. - /// - public static SQLiteOpenDataSource AsDataSource(this SQLiteConnection connection, SQLiteTransaction transaction) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); + /// + /// Returns a data source wrapped around the transaction. + /// + /// The connection. + /// The transaction. + /// SqlServerOpenDataSource. + /// + public static SQLiteOpenDataSource AsDataSource(this SQLiteConnection connection, SQLiteTransaction transaction) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SQLiteDataSource(cs)); - return new SQLiteOpenDataSource(dataSourceBase, connection, transaction); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SQLiteDataSource(cs)); + return new SQLiteOpenDataSource(dataSourceBase, connection, transaction); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteLimitOption.cs b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteLimitOption.cs index ccfc5e0e3..f802b00d6 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteLimitOption.cs +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/SQLiteLimitOption.cs @@ -1,26 +1,23 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Limit options supported by SQL Server. +/// +/// This is a strict subset of LimitOptions +public enum SQLiteLimitOption { /// - /// Limit options supported by SQL Server. + /// No limits were applied. /// - /// This is a strict subset of LimitOptions - public enum SQLiteLimitOption - { - /// - /// No limits were applied. - /// - None = LimitOptions.None, - - /// - /// Uses OFFSET/FETCH - /// - Rows = LimitOptions.Rows, - - /// - /// Randomly sample the indicated number of rows - /// - RandomSampleRows = LimitOptions.RandomSampleRows, + None = LimitOptions.None, + /// + /// Uses OFFSET/FETCH + /// + Rows = LimitOptions.Rows, - } + /// + /// Randomly sample the indicated number of rows + /// + RandomSampleRows = LimitOptions.RandomSampleRows, } diff --git a/Tortuga.Chain/Tortuga.Chain.SQLite/Tortuga.Chain.SQLite.csproj b/Tortuga.Chain/Tortuga.Chain.SQLite/Tortuga.Chain.SQLite.csproj index 8ef7a0cfd..edcf5fb4f 100644 --- a/Tortuga.Chain/Tortuga.Chain.SQLite/Tortuga.Chain.SQLite.csproj +++ b/Tortuga.Chain/Tortuga.Chain.SQLite/Tortuga.Chain.SQLite.csproj @@ -11,7 +11,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -61,7 +61,7 @@ - + @@ -87,7 +87,7 @@ - true + Generated @@ -95,7 +95,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index 99b4a3914..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* -Container class: Tortuga.Chain.SqlServerDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.SqlServer.SqlServerDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsTruncateTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsInsertBatchTrait> - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait - Adding trait: Traits.SupportsUpsertTrait - Adding trait: Traits.SupportsInsertBulkTrait - Adding trait: Traits.SupportsScalarFunctionTrait - Adding trait: Traits.SupportsProcedureTrait - Adding trait: Traits.SupportsTableFunctionTrait -Container class: Tortuga.Chain.SqlServer.SqlServerOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerDataSourceBase.cs deleted file mode 100644 index ac9e57277..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerDataSourceBase.cs +++ /dev/null @@ -1,1408 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class SqlServerDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsTruncate, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsInsertBatch, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Tortuga.Chain.DataSources.ISupportsUpsert, Tortuga.Chain.DataSources.ISupportsInsertBulk, Tortuga.Chain.DataSources.ISupportsScalarFunction, Tortuga.Chain.DataSources.ISupportsProcedure, Tortuga.Chain.DataSources.ISupportsTableFunction, Traits.ICommandHelper, Traits.IInsertBatchHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper, Traits.IUpsertHelper, Traits.IInsertBulkHelper, Traits.ICommandHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsTruncateTrait ___Trait1 = new(); - private Traits.SupportsTruncateTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait2 = new(); - private Traits.SupportsSqlQueriesTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsInsertBatchTrait> ___Trait3 = new(); - private Traits.SupportsInsertBatchTrait> __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait4 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsDeleteTrait ___Trait5 = new(); - private Traits.SupportsDeleteTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsUpdateTrait ___Trait6 = new(); - private Traits.SupportsUpdateTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait7 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsInsertTrait ___Trait8 = new(); - private Traits.SupportsInsertTrait __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsUpdateSet ___Trait9 = new(); - private Traits.SupportsUpdateSet __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsDeleteSet ___Trait10 = new(); - private Traits.SupportsDeleteSet __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - private Traits.SupportsFromTrait ___Trait11 = new(); - private Traits.SupportsFromTrait __Trait11 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait11; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait12 = new(); - private Traits.SupportsGetByKeyListTrait __Trait12 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait12; - } - } - private Traits.SupportsUpsertTrait ___Trait13 = new(); - private Traits.SupportsUpsertTrait __Trait13 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait13; - } - } - private Traits.SupportsInsertBulkTrait ___Trait14 = new(); - private Traits.SupportsInsertBulkTrait __Trait14 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait14; - } - } - private Traits.SupportsScalarFunctionTrait ___Trait15 = new(); - private Traits.SupportsScalarFunctionTrait __Trait15 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait15; - } - } - private Traits.SupportsProcedureTrait ___Trait16 = new(); - private Traits.SupportsProcedureTrait __Trait16 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait16; - } - } - private Traits.SupportsTableFunctionTrait ___Trait17 = new(); - private Traits.SupportsTableFunctionTrait __Trait17 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait17; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait5).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait5).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait4).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBatch - Tortuga.Chain.CommandBuilders.IDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertBatch(objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.String tableName, System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(tableName, objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(objects, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBulk - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, objects); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(objects); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsProcedure - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName); - } - - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsScalarFunction - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName); - } - - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait2).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTableFunction - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait17).TableFunction(functionName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait17).TableFunction(functionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTruncate - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate() - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait6).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait6).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait7).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, newValues, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(argumentValue, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.SqlServer.SqlServerObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait10.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait10.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait10.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait10.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait5.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait5.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName) - { - return __Trait11.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.String whereClause) - { - return __Trait11.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait11.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait11.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait11.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait11.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait11.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait11.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TKey key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertBatchTrait> - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// Name of the table. - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder InsertBatch(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(objects, options); - } - - /// - /// Performs a series of batch inserts. - /// - /// The type of the t object. - /// Name of the table. - /// The objects. - /// The options. - /// Tortuga.Chain.ILink<System.Int32>. - /// This operation is not atomic. It should be wrapped in a transaction. - public Tortuga.Chain.ILink InsertMultipleBatch(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.ILink InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(objects, options); - } - - // Exposing trait Traits.SupportsInsertBulkTrait - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data table. - /// TInsertBulkCommand. - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Data.DataTable dataTable) - { - return __Trait14.InsertBulk(tableName, dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data reader. - /// TInsertBulkCommand. - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Data.IDataReader dataReader) - { - return __Trait14.InsertBulk(tableName, dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// - /// Name of the table. - /// The objects. - /// TInsertBulkCommand. - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(tableName, objects); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data table. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(System.Data.DataTable dataTable)where TObject : class - { - return __Trait14.InsertBulk(dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data reader. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(System.Data.IDataReader dataReader)where TObject : class - { - return __Trait14.InsertBulk(dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The objects. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(objects); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsProcedureTrait - - /// - /// Loads a procedure definition - /// - /// Name of the procedure. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName) - { - return __Trait16.Procedure(procedureName); - } - - /// - /// Loads a procedure definition and populates it using the parameter object. - /// - /// Name of the procedure. - /// The argument value. - /// - /// - /// The procedure's definition is loaded from the database and used to determine which properties on the parameter object to use. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName, System.Object argumentValue) - { - return __Trait16.Procedure(procedureName, argumentValue); - } - - // Exposing trait Traits.SupportsScalarFunctionTrait - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName) - { - return __Trait15.ScalarFunction(scalarFunctionName); - } - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName, System.Object functionArgumentValue) - { - return __Trait15.ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait2.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait2.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsTableFunctionTrait - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName) - { - return __Trait17.TableFunction(tableFunctionName); - } - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName, System.Object functionArgumentValue) - { - return __Trait17.TableFunction(tableFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsTruncateTrait - - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate(Tortuga.Chain.SqlServer.SqlServerObjectName tableName) - { - return __Trait1.Truncate(tableName); - } - - /// Truncates the specified table. - /// This class used to determine which table to Truncate - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate()where TObject : class - { - return __Trait1.Truncate(); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait6.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait6.Update(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsUpsertTrait - - /// - /// Creates a operation used to perform an "upsert" operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(tableName, argumentValue, options); - } - - /// - /// Perform an insert or update operation as appropriate. - /// - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.SqlServer.SqlServerObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder OnProcedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder OnScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.TableDbCommandBuilder OnTableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName, System.Object? functionArgumentValue ); - - private partial Tortuga.Chain.ILink OnTruncate(Tortuga.Chain.SqlServer.SqlServerObjectName tableName ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.OnTruncate = OnTruncate; - __Trait1.DataSource = this; - __Trait2.OnSql = OnSql; - __Trait3.DataSource = this; - __Trait4.DataSource = this; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - __Trait11.DataSource = this; - __Trait12.DataSource = this; - __Trait13.DataSource = this; - __Trait14.DataSource = this; - __Trait15.OnScalarFunction = OnScalarFunction; - __Trait15.DataSource = this; - __Trait16.OnProcedure = OnProcedure; - __Trait16.DataSource = this; - __Trait17.OnTableFunction = OnTableFunction; - __Trait17.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerOpenDataSource.cs deleted file mode 100644 index c5618fc73..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class SqlServerOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public Microsoft.Data.SqlClient.SqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public Microsoft.Data.SqlClient.SqlTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SqlServer.SqlServerMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.SqlServerDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private Microsoft.Data.SqlClient.SqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private Microsoft.Data.SqlClient.SqlTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SqlServer.SqlServerOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource.cs deleted file mode 100644 index 4c9abb7c8..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class SqlServerTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public Microsoft.Data.SqlClient.SqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public Microsoft.Data.SqlClient.SqlTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SqlServer.SqlServerMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.SqlServerDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private Microsoft.Data.SqlClient.SqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private Microsoft.Data.SqlClient.SqlTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServerDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServerDataSource.cs deleted file mode 100644 index 565e37889..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServerDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class SqlServerDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public Microsoft.Data.SqlClient.SqlConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource CreateOpenDataSource(Microsoft.Data.SqlClient.SqlConnection connection, Microsoft.Data.SqlClient.SqlTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private Microsoft.Data.SqlClient.SqlConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.SqlServerDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServerDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServerDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SqlServerDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SqlServerDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial Microsoft.Data.SqlClient.SqlConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SqlServer.SqlServerOpenDataSource OnCreateOpenDataSource(Microsoft.Data.SqlClient.SqlConnection connection, Microsoft.Data.SqlClient.SqlTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Tortuga.Chain.SqlServer.MDS.csproj b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Tortuga.Chain.SqlServer.MDS.csproj index 372794622..6cac48abe 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Tortuga.Chain.SqlServer.MDS.csproj +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.MDS/Tortuga.Chain.SqlServer.MDS.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -70,7 +70,7 @@ - + @@ -86,7 +86,7 @@ - true + Generated @@ -94,7 +94,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index 8edce975c..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* -Container class: Tortuga.Chain.OleDbSqlServerDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.SqlServer.OleDbSqlServerDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsTruncateTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait - Adding trait: Traits.SupportsUpsertTrait - Adding trait: Traits.SupportsScalarFunctionTrait - Adding trait: Traits.SupportsProcedureTrait - Adding trait: Traits.SupportsTableFunctionTrait -Container class: Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.OleDbSqlServerDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.OleDbSqlServerDataSource.cs deleted file mode 100644 index ab0bcdeaf..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.OleDbSqlServerDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class OleDbSqlServerDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public System.Data.OleDb.OleDbConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource CreateOpenDataSource(System.Data.OleDb.OleDbConnection connection, System.Data.OleDb.OleDbTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private System.Data.OleDb.OleDbConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.OleDbSqlServerDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.OleDbSqlServerDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.OleDbSqlServerDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.OleDbSqlServerDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.OleDbSqlServerDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial System.Data.OleDb.OleDbConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource OnCreateOpenDataSource(System.Data.OleDb.OleDbConnection connection, System.Data.OleDb.OleDbTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerDataSourceBase.cs deleted file mode 100644 index 21bf8365f..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerDataSourceBase.cs +++ /dev/null @@ -1,1213 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class OleDbSqlServerDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsTruncate, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Tortuga.Chain.DataSources.ISupportsUpsert, Tortuga.Chain.DataSources.ISupportsScalarFunction, Tortuga.Chain.DataSources.ISupportsProcedure, Tortuga.Chain.DataSources.ISupportsTableFunction, Traits.ICommandHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper, Traits.IUpsertHelper, Traits.ICommandHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsTruncateTrait ___Trait1 = new(); - private Traits.SupportsTruncateTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait2 = new(); - private Traits.SupportsSqlQueriesTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait3 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsDeleteTrait ___Trait4 = new(); - private Traits.SupportsDeleteTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsUpdateTrait ___Trait5 = new(); - private Traits.SupportsUpdateTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait6 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsInsertTrait ___Trait7 = new(); - private Traits.SupportsInsertTrait __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsUpdateSet ___Trait8 = new(); - private Traits.SupportsUpdateSet __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsDeleteSet ___Trait9 = new(); - private Traits.SupportsDeleteSet __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsFromTrait ___Trait10 = new(); - private Traits.SupportsFromTrait __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait11 = new(); - private Traits.SupportsGetByKeyListTrait __Trait11 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait11; - } - } - private Traits.SupportsUpsertTrait ___Trait12 = new(); - private Traits.SupportsUpsertTrait __Trait12 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait12; - } - } - private Traits.SupportsScalarFunctionTrait ___Trait13 = new(); - private Traits.SupportsScalarFunctionTrait __Trait13 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait13; - } - } - private Traits.SupportsProcedureTrait ___Trait14 = new(); - private Traits.SupportsProcedureTrait __Trait14 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait14; - } - } - private Traits.SupportsTableFunctionTrait ___Trait15 = new(); - private Traits.SupportsTableFunctionTrait __Trait15 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait15; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait4).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait4).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait3).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait3).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait3).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait9).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait9).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait9).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait10).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait11).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait11).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait11).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait11).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait11).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait11).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait11).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait7).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait7).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsProcedure - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait14).Procedure(procedureName); - } - - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait14).Procedure(procedureName, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsScalarFunction - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait13).ScalarFunction(scalarFunctionName); - } - - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait13).ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait2).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTableFunction - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait15).TableFunction(functionName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait15).TableFunction(functionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTruncate - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate() - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait5).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait6).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait6).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait6).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait8).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait8).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait8).UpdateSet(tableName, newValues, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait12).Upsert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait12).Upsert(argumentValue, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.SqlServer.SqlServerObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait3.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait3.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait3.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait3.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait3.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait3.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait3.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait9.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait9.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait9.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait9.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait4.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait4.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName) - { - return __Trait10.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.String whereClause) - { - return __Trait10.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait10.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait10.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait10.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait10.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait10.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait10.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait11.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait11.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait11.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait11.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait11.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String key) - { - return __Trait11.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TKey key) - { - return __Trait11.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait11.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait11.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait11.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait11.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait11.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait11.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait11.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait7.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait7.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsProcedureTrait - - /// - /// Loads a procedure definition - /// - /// Name of the procedure. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName) - { - return __Trait14.Procedure(procedureName); - } - - /// - /// Loads a procedure definition and populates it using the parameter object. - /// - /// Name of the procedure. - /// The argument value. - /// - /// - /// The procedure's definition is loaded from the database and used to determine which properties on the parameter object to use. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName, System.Object argumentValue) - { - return __Trait14.Procedure(procedureName, argumentValue); - } - - // Exposing trait Traits.SupportsScalarFunctionTrait - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName) - { - return __Trait13.ScalarFunction(scalarFunctionName); - } - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName, System.Object functionArgumentValue) - { - return __Trait13.ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait2.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait2.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsTableFunctionTrait - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName) - { - return __Trait15.TableFunction(tableFunctionName); - } - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName, System.Object functionArgumentValue) - { - return __Trait15.TableFunction(tableFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsTruncateTrait - - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate(Tortuga.Chain.SqlServer.SqlServerObjectName tableName) - { - return __Trait1.Truncate(tableName); - } - - /// Truncates the specified table. - /// This class used to determine which table to Truncate - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate()where TObject : class - { - return __Trait1.Truncate(); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait6.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait6.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait6.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait8.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait8.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait8.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait8.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait8.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait8.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait5.Update(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsUpsertTrait - - /// - /// Creates a operation used to perform an "upsert" operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait12.Upsert(tableName, argumentValue, options); - } - - /// - /// Perform an insert or update operation as appropriate. - /// - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait12.Upsert(argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.SqlServer.SqlServerObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder OnProcedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder OnScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.TableDbCommandBuilder OnTableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName, System.Object? functionArgumentValue ); - - private partial Tortuga.Chain.ILink OnTruncate(Tortuga.Chain.SqlServer.SqlServerObjectName tableName ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.OnTruncate = OnTruncate; - __Trait1.DataSource = this; - __Trait2.OnSql = OnSql; - __Trait3.DataSource = this; - __Trait4.DataSource = this; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - __Trait11.DataSource = this; - __Trait12.DataSource = this; - __Trait13.OnScalarFunction = OnScalarFunction; - __Trait13.DataSource = this; - __Trait14.OnProcedure = OnProcedure; - __Trait14.DataSource = this; - __Trait15.OnTableFunction = OnTableFunction; - __Trait15.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource.cs deleted file mode 100644 index a5b1b664a..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class OleDbSqlServerOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.OleDb.OleDbConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.OleDb.OleDbTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SqlServer.OleDbSqlServerMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.OleDbSqlServerDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.OleDb.OleDbConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Data.OleDb.OleDbTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SqlServer.OleDbSqlServerOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource.cs deleted file mode 100644 index b103159ff..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.OleDbSqlServerTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class OleDbSqlServerTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.OleDb.OleDbConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.OleDb.OleDbTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SqlServer.OleDbSqlServerMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.OleDbSqlServerDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.OleDb.OleDbConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private System.Data.OleDb.OleDbTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/OleDbSqlServerDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/OleDbSqlServerDataSource.cs index bdd22f1fe..cd165e675 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/OleDbSqlServerDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/OleDbSqlServerDataSource.cs @@ -5,427 +5,407 @@ using Tortuga.Chain.Core; using Tortuga.Chain.SqlServer; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class OleDbSqlServerDataSource. +/// +/// +public partial class OleDbSqlServerDataSource : OleDbSqlServerDataSourceBase { + OleDbSqlServerMetadataCache m_DatabaseMetadata; + + /// + /// This is used to decide which option overrides to set when establishing a connection. + /// + OleDbSqlServerEffectiveSettings? m_ServerDefaultSettings; + /// - /// Class OleDbSqlServerDataSource. + /// Initializes a new instance of the class. /// - /// - public partial class OleDbSqlServerDataSource : OleDbSqlServerDataSourceBase + /// Name of the data source. + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + public OleDbSqlServerDataSource(string? name, string connectionString, SqlServerDataSourceSettings? settings = null) : base(settings) { - OleDbSqlServerMetadataCache m_DatabaseMetadata; - - /// - /// This is used to decide which option overrides to set when establishing a connection. - /// - OleDbSqlServerEffectiveSettings? m_ServerDefaultSettings; - - /// - /// Initializes a new instance of the class. - /// - /// Name of the data source. - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - public OleDbSqlServerDataSource(string? name, string connectionString, SqlServerDataSourceSettings? settings = null) : base(settings) + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + + m_ConnectionBuilder = new OleDbConnectionStringBuilder(connectionString); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; + + m_DatabaseMetadata = new OleDbSqlServerMetadataCache(m_ConnectionBuilder); + + if (settings != null) { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException($"{nameof(connectionString)} is null or empty.", nameof(connectionString)); + XactAbort = settings.XactAbort; + ArithAbort = settings.ArithAbort; + } - m_ConnectionBuilder = new OleDbConnectionStringBuilder(connectionString); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - m_DatabaseMetadata = new OleDbSqlServerMetadataCache(m_ConnectionBuilder); + /// + /// Initializes a new instance of the class. + /// + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + public OleDbSqlServerDataSource(string connectionString, SqlServerDataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - if (settings != null) - { - XactAbort = settings.XactAbort; - ArithAbort = settings.ArithAbort; - } + /// + /// Initializes a new instance of the class. + /// + /// Optional name of the data source. + /// The connection string builder. + /// Optional settings object. + /// connectionStringBuilder;connectionStringBuilder is null. + public OleDbSqlServerDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) : base(settings) + { + m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + m_DatabaseMetadata = new OleDbSqlServerMetadataCache(m_ConnectionBuilder); - /// - /// Initializes a new instance of the class. - /// - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - public OleDbSqlServerDataSource(string connectionString, SqlServerDataSourceSettings? settings = null) - : this(null, connectionString, settings) + if (settings != null) { + XactAbort = settings.XactAbort; + ArithAbort = settings.ArithAbort; } + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - /// - /// Initializes a new instance of the class. - /// - /// Optional name of the data source. - /// The connection string builder. - /// Optional settings object. - /// connectionStringBuilder;connectionStringBuilder is null. - public OleDbSqlServerDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) : base(settings) - { - m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + /// + /// Initializes a new instance of the class. + /// + /// The connection string builder. + /// Optional settings object. + public OleDbSqlServerDataSource(OleDbConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) + : this(null, connectionStringBuilder, settings) + { + } - m_DatabaseMetadata = new OleDbSqlServerMetadataCache(m_ConnectionBuilder); + OleDbSqlServerDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings settings, OleDbSqlServerMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + { + m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.DataSource; + else + Name = name; - if (settings != null) - { - XactAbort = settings.XactAbort; - ArithAbort = settings.ArithAbort; - } - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + m_DatabaseMetadata = databaseMetadata; - OleDbSqlServerDataSource(string? name, OleDbConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings settings, OleDbSqlServerMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + if (settings != null) { - m_ConnectionBuilder = connectionStringBuilder ?? throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.DataSource; - else - Name = name; + XactAbort = settings.XactAbort; + ArithAbort = settings.ArithAbort; + } + m_ExtensionCache = extensionCache; + m_Cache = cache; + } - m_DatabaseMetadata = databaseMetadata; + /// + /// Terminates a query when an overflow or divide-by-zero error occurs during query execution. + /// + /// Microsoft recommends setting ArithAbort=On for all connections. To avoid an additional round-trip to the server, do this at the server level instead of at the connection level. + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool? ArithAbort { get; } - if (settings != null) - { - XactAbort = settings.XactAbort; - ArithAbort = settings.ArithAbort; - } - m_ExtensionCache = extensionCache; - m_Cache = cache; - } + /// + /// This object can be used to lookup database information. + /// + public override OleDbSqlServerMetadataCache DatabaseMetadata + { + get { return m_DatabaseMetadata; } + } + + /// + /// Rolls back a transaction if a Transact-SQL statement raises a run-time error. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] + public bool? XactAbort { get; } + + /// + /// Creates a new transaction + /// + /// optional name of the transaction. + /// the isolation level. if not supplied, will use the database default. + /// if true, logging events are forwarded to the parent connection. + /// + /// + /// the caller of this function is responsible for closing the transaction. + /// + public virtual OleDbSqlServerTransactionalDataSource BeginTransaction(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true) + { + return new OleDbSqlServerTransactionalDataSource(this, transactionName, isolationLevel, forwardEvents); + } + + /// + /// Creates a new transaction + /// + /// Name of the transaction. + /// The isolation level. + /// if set to true [forward events]. + /// + /// + public async Task BeginTransactionAsync(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true, CancellationToken cancellationToken = default) + { + var connection = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false); + + OleDbTransaction transaction; + if (isolationLevel.HasValue) + transaction = connection.BeginTransaction(isolationLevel.Value); + else + transaction = connection.BeginTransaction(); + return new OleDbSqlServerTransactionalDataSource(this, transactionName, forwardEvents, connection, transaction); + } + + /// + /// Gets the options that are currently in effect. This takes into account server-defined defaults. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public OleDbSqlServerEffectiveSettings GetEffectiveSettings() + { + var result = new OleDbSqlServerEffectiveSettings(); + using (var con = CreateConnection()) + result.Reload(con, null); + return result; + } + + /// + /// Gets the options that are currently in effect. This takes into account server-defined defaults. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public async Task GetEffectiveSettingsAsync() + { + var result = new OleDbSqlServerEffectiveSettings(); + using (var con = await CreateConnectionAsync().ConfigureAwait(false)) + await result.ReloadAsync(con, null).ConfigureAwait(false); + return result; + } - /// - /// Initializes a new instance of the class. - /// - /// The connection string builder. - /// Optional settings object. - public OleDbSqlServerDataSource(OleDbConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) - : this(null, connectionStringBuilder, settings) + /// + /// Creates a new data source with the indicated changes to the settings. + /// + /// The new settings to use. + /// + /// The new data source will share the same database metadata cache. + public OleDbSqlServerDataSource WithSettings(SqlServerDataSourceSettings? settings) + { + var mergedSettings = new SqlServerDataSourceSettings() { - } + DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, + SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, + StrictMode = settings?.StrictMode ?? StrictMode, + SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode, + XactAbort = settings?.XactAbort ?? XactAbort, + ArithAbort = settings?.ArithAbort ?? ArithAbort + }; + var result = new OleDbSqlServerDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); + result.m_DatabaseMetadata = m_DatabaseMetadata; + result.AuditRules = AuditRules; + result.UserValue = UserValue; + + result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); + result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); + result.ExecutionError += (sender, e) => OnExecutionError(e); + result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); + + return result; + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Terminates a query when an overflow or divide-by-zero error occurs during query execution. - /// - /// Microsoft recommends setting ArithAbort=On for all connections. To avoid an additional round-trip to the server, do this at the server level instead of at the connection level. - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool? ArithAbort { get; } - - /// - /// This object can be used to lookup database information. - /// - public override OleDbSqlServerMetadataCache DatabaseMetadata + try { - get { return m_DatabaseMetadata; } - } + using (var con = CreateConnection()) + { + using (var cmd = new OleDbCommand()) + { + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); - /// - /// Rolls back a transaction if a Transact-SQL statement raises a run-time error. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] - public bool? XactAbort { get; } - - /// - /// Creates a new transaction - /// - /// optional name of the transaction. - /// the isolation level. if not supplied, will use the database default. - /// if true, logging events are forwarded to the parent connection. - /// - /// - /// the caller of this function is responsible for closing the transaction. - /// - public virtual OleDbSqlServerTransactionalDataSource BeginTransaction(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true) + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + } + } + catch (Exception ex) { - return new OleDbSqlServerTransactionalDataSource(this, transactionName, isolationLevel, forwardEvents); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } - /// - /// Creates a new transaction - /// - /// Name of the transaction. - /// The isolation level. - /// if set to true [forward events]. - /// - /// - public async Task BeginTransactionAsync(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true, CancellationToken cancellationToken = default) - { - var connection = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false); + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - OleDbTransaction transaction; - if (isolationLevel.HasValue) - transaction = connection.BeginTransaction(isolationLevel.Value); - else - transaction = connection.BeginTransaction(); - return new OleDbSqlServerTransactionalDataSource(this, transactionName, forwardEvents, connection, transaction); - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Gets the options that are currently in effect. This takes into account server-defined defaults. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public OleDbSqlServerEffectiveSettings GetEffectiveSettings() + try { - var result = new OleDbSqlServerEffectiveSettings(); using (var con = CreateConnection()) - result.Reload(con, null); - return result; + { + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } } - - /// - /// Gets the options that are currently in effect. This takes into account server-defined defaults. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public async Task GetEffectiveSettingsAsync() + catch (Exception ex) { - var result = new OleDbSqlServerEffectiveSettings(); - using (var con = await CreateConnectionAsync().ConfigureAwait(false)) - await result.ReloadAsync(con, null).ConfigureAwait(false); - return result; + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try - { - using (var con = CreateConnection()) - { - using (var cmd = new OleDbCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) + using (var con = CreateConnection()) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = CreateConnection()) - { - var rows = implementation(con, null); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - using (var con = CreateConnection()) + using (var cmd = new OleDbCommand()) { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } } - catch (Exception ex) - { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } - } } - - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - using (var cmd = new OleDbCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - string? BuildConnectionSettingsOverride() - { - if (m_ServerDefaultSettings == null) - throw new InvalidOperationException("m_ServerDefaultSettings was not set before building connection settings."); - - if (ArithAbort == null && XactAbort == null) - return null; - - var sql = new StringBuilder(); - - if (ArithAbort.HasValue && ArithAbort != m_ServerDefaultSettings.ArithAbort) - sql.AppendLine("SET ARITHABORT " + (ArithAbort.Value ? "ON" : "OFF")); - if (XactAbort.HasValue && XactAbort != m_ServerDefaultSettings.XactAbort) - sql.AppendLine("SET XACT_ABORT " + (XactAbort.Value ? "ON" : "OFF")); - - return sql.ToString(); - } + string? BuildConnectionSettingsOverride() + { + if (m_ServerDefaultSettings == null) + throw new InvalidOperationException("m_ServerDefaultSettings was not set before building connection settings."); + if (ArithAbort == null && XactAbort == null) + return null; + var sql = new StringBuilder(); - /// - /// Creates a new data source with the indicated changes to the settings. - /// - /// The new settings to use. - /// - /// The new data source will share the same database metadata cache. - public OleDbSqlServerDataSource WithSettings(SqlServerDataSourceSettings? settings) - { - var mergedSettings = new SqlServerDataSourceSettings() - { - DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, - SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, - StrictMode = settings?.StrictMode ?? StrictMode, - SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode, - XactAbort = settings?.XactAbort ?? XactAbort, - ArithAbort = settings?.ArithAbort ?? ArithAbort - }; - var result = new OleDbSqlServerDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); - result.m_DatabaseMetadata = m_DatabaseMetadata; - result.AuditRules = AuditRules; - result.UserValue = UserValue; - - result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); - result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); - result.ExecutionError += (sender, e) => OnExecutionError(e); - result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); - - return result; - } + if (ArithAbort.HasValue && ArithAbort != m_ServerDefaultSettings.ArithAbort) + sql.AppendLine("SET ARITHABORT " + (ArithAbort.Value ? "ON" : "OFF")); + if (XactAbort.HasValue && XactAbort != m_ServerDefaultSettings.XactAbort) + sql.AppendLine("SET XACT_ABORT " + (XactAbort.Value ? "ON" : "OFF")); + return sql.ToString(); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteObject.cs index 49476dd9e..5be445a63 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteObject.cs @@ -1,64 +1,62 @@ -using System; -using System.Data.OleDb; +using System.Data.OleDb; using System.Text; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerDeleteObject. +/// +internal sealed class OleDbSqlServerDeleteObject : OleDbSqlServerObjectCommand + where TArgument : class { + readonly DeleteOptions m_Options; + /// - /// Class SqlServerDeleteObject. + /// Initializes a new instance of the class. /// - internal sealed class OleDbSqlServerDeleteObject : OleDbSqlServerObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public OleDbSqlServerDeleteObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, DeleteOptions options) : base(dataSource, tableName, argumentValue) { - readonly DeleteOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public OleDbSqlServerDeleteObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, DeleteOptions options) : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); - - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; + m_Options = options; + } - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - sql.Append(header); - sql.Append("DELETE FROM " + Table.Name.ToQuotedString()); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); - sqlBuilder.BuildAnonymousWhereClause(sql, " WHERE ", null, true); - sql.Append(";"); - sql.Append(footer); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. - return new OleDbCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); - } + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); + + var sql = new StringBuilder(); + string? header; + string? intoClause; + string? footer; + + sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); + sql.Append(header); + sql.Append("DELETE FROM " + Table.Name.ToQuotedString()); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); + sqlBuilder.BuildAnonymousWhereClause(sql, " WHERE ", null, true); + sql.Append(";"); + sql.Append(footer); + + return new OleDbCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteSet.cs index 110c2d35b..f49e0b4fd 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerDeleteSet.cs @@ -5,142 +5,141 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerDeleteSet. +/// +internal sealed class OleDbSqlServerDeleteSet : MultipleRowDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly int? m_ExpectedRowCount; + readonly FilterOptions m_FilterOptions; + readonly object? m_FilterValue; + readonly DeleteOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly SqlServerTableOrViewMetadata m_Table; + readonly string? m_WhereClause; + /// - /// Class SqlServerDeleteSet. + /// Initializes a new instance of the class. /// - internal sealed class OleDbSqlServerDeleteSet : MultipleRowDbCommandBuilder + /// The data source. + /// Name of the table. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public OleDbSqlServerDeleteSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly FilterOptions m_FilterOptions; - readonly object? m_FilterValue; - readonly IEnumerable? m_Parameters; - readonly SqlServerTableOrViewMetadata m_Table; - readonly string? m_WhereClause; - readonly DeleteOptions m_Options; - readonly int? m_ExpectedRowCount; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public OleDbSqlServerDeleteSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) - { - if (options.HasFlag(DeleteOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_Parameters = parameters; - m_Options = options; - m_ExpectedRowCount = expectedRowCount; - } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The argument value. - public OleDbSqlServerDeleteSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string? whereClause, object? argumentValue) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The filter value. - /// The options. - public OleDbSqlServerDeleteSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. + if (options.HasFlag(DeleteOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_Parameters = parameters; + m_Options = options; + m_ExpectedRowCount = expectedRowCount; + } - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The where clause. + /// The argument value. + public OleDbSqlServerDeleteSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string? whereClause, object? argumentValue) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + } - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The filter value. + /// The options. + public OleDbSqlServerDeleteSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + } - List parameters; - var sql = new StringBuilder(); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. - sqlBuilder.UseTableVariable(m_Table, out var header, out var intoClause, out var footer); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - sql.Append(header); - sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions)); + List parameters; + var sql = new StringBuilder(); - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); + sqlBuilder.UseTableVariable(m_Table, out var header, out var intoClause, out var footer); - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } - sql.Append(";"); - sql.Append(footer); + sql.Append(header); + sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); - if (m_Parameters != null) - parameters.AddRange(m_Parameters); + if (m_FilterValue != null) + { + sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions)); - return new OleDbCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); + parameters = sqlBuilder.GetParameters(); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - return m_Table.Columns.TryGetColumn(columnName); + parameters = sqlBuilder.GetParameters(); } + sql.Append(";"); + sql.Append(footer); - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + if (m_Parameters != null) + parameters.AddRange(m_Parameters); + + return new OleDbCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); } -} + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertObject .cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertObject .cs index ed5947adf..ae57e9431 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertObject .cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertObject .cs @@ -1,70 +1,68 @@ -using System; -using System.Data.OleDb; +using System.Data.OleDb; using System.Text; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerInsertObject. +/// +internal sealed class OleDbSqlServerInsertObject : OleDbSqlServerObjectCommand + where TArgument : class { - /// - /// Class OleDbSqlServerInsertObject. - /// - internal sealed class OleDbSqlServerInsertObject : OleDbSqlServerObjectCommand - where TArgument : class - { - readonly InsertOptions m_Options; + readonly InsertOptions m_Options; - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public OleDbSqlServerInsertObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, InsertOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public OleDbSqlServerInsertObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, InsertOptions options) + : base(dataSource, tableName, argumentValue) + { + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; + var sql = new StringBuilder(); + string? header; + string? intoClause; + string? footer; - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - sql.Append(header); + sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); + sql.Append(header); - bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} ON;"); + bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} ON;"); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToQuotedString()} (", null, ")", identityInsert); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); - sqlBuilder.BuildAnonymousValuesClause(sql, " VALUES (", ")", identityInsert); - sql.Append(";"); + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToQuotedString()} (", null, ")", identityInsert); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); + sqlBuilder.BuildAnonymousValuesClause(sql, " VALUES (", ")", identityInsert); + sql.Append(";"); - sql.Append(footer); + sql.Append(footer); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} OFF;"); + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} OFF;"); - return new OleDbCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); - } - } + return new OleDbCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); + } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertOrUpdateObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertOrUpdateObject.cs index d33d2f8a2..26aa26a5e 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertOrUpdateObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerInsertOrUpdateObject.cs @@ -1,79 +1,75 @@ -using System; -using System.Data; -using System.Data.OleDb; -using System.Linq; +using System.Data.OleDb; using System.Text; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerInsertOrUpdateObject. +/// +internal sealed class OleDbSqlServerInsertOrUpdateObject : OleDbSqlServerObjectCommand + where TArgument : class { - /// - /// Class OleDbSqlServerInsertOrUpdateObject. - /// - internal sealed class OleDbSqlServerInsertOrUpdateObject : OleDbSqlServerObjectCommand - where TArgument : class - { - readonly UpsertOptions m_Options; + readonly UpsertOptions m_Options; - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public OleDbSqlServerInsertOrUpdateObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpsertOptions options) : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public OleDbSqlServerInsertOrUpdateObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpsertOptions options) : base(dataSource, tableName, argumentValue) + { + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var availableColumns = sqlBuilder.GetParameterizedColumns().ToList(); + var availableColumns = sqlBuilder.GetParameterizedColumns().ToList(); - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; + var sql = new StringBuilder(); + string? header; + string? intoClause; + string? footer; - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); + sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - sql.Append(header); - sql.Append($"MERGE INTO {Table.Name.ToQuotedString()} target USING "); - sql.Append("(VALUES (" + string.Join(", ", availableColumns.Select(c => "?")) + ")) AS source (" + string.Join(", ", availableColumns.Select(c => c.QuotedSqlName)) + ")"); - sql.Append(" ON "); - sql.Append(string.Join(" AND ", sqlBuilder.GetKeyColumns().ToList().Select(c => $"target.{c.QuotedSqlName} = source.{c.QuotedSqlName}"))); + sql.Append(header); + sql.Append($"MERGE INTO {Table.Name.ToQuotedString()} target USING "); + sql.Append("(VALUES (" + string.Join(", ", availableColumns.Select(c => "?")) + ")) AS source (" + string.Join(", ", availableColumns.Select(c => c.QuotedSqlName)) + ")"); + sql.Append(" ON "); + sql.Append(string.Join(" AND ", sqlBuilder.GetKeyColumns().ToList().Select(c => $"target.{c.QuotedSqlName} = source.{c.QuotedSqlName}"))); - sql.Append(" WHEN MATCHED THEN UPDATE SET "); - sql.Append(string.Join(", ", sqlBuilder.GetUpdateColumns().Select(x => $"{x.QuotedSqlName} = source.{x.QuotedSqlName}"))); + sql.Append(" WHEN MATCHED THEN UPDATE SET "); + sql.Append(string.Join(", ", sqlBuilder.GetUpdateColumns().Select(x => $"{x.QuotedSqlName} = source.{x.QuotedSqlName}"))); - var insertColumns = sqlBuilder.GetInsertColumns(); - sql.Append(" WHEN NOT MATCHED THEN INSERT ("); - sql.Append(string.Join(", ", insertColumns.Select(x => x.QuotedSqlName))); - sql.Append(") VALUES ("); - sql.Append(string.Join(", ", insertColumns.Select(x => "source." + x.QuotedSqlName))); - sql.Append(" )"); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); - sql.Append(";"); - sql.Append(footer); + var insertColumns = sqlBuilder.GetInsertColumns(); + sql.Append(" WHEN NOT MATCHED THEN INSERT ("); + sql.Append(string.Join(", ", insertColumns.Select(x => x.QuotedSqlName))); + sql.Append(") VALUES ("); + sql.Append(string.Join(", ", insertColumns.Select(x => "source." + x.QuotedSqlName))); + sql.Append(" )"); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); + sql.Append(";"); + sql.Append(footer); - return new OleDbCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); - } - } + return new OleDbCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); + } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerObjectCommand.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerObjectCommand.cs index c1012577e..de0fce593 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerObjectCommand.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerObjectCommand.cs @@ -2,46 +2,45 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerObjectCommand. +/// +/// The type of the argument. +internal abstract class OleDbSqlServerObjectCommand : ObjectDbCommandBuilder + where TArgument : class { - /// - /// Class OleDbSqlServerObjectCommand. - /// - /// The type of the argument. - internal abstract class OleDbSqlServerObjectCommand : ObjectDbCommandBuilder - where TArgument : class - { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - protected OleDbSqlServerObjectCommand(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue) - : base(dataSource, argumentValue) - { - Table = DataSource.DatabaseMetadata.GetTableOrView(tableName); - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The argument value. + protected OleDbSqlServerObjectCommand(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue) + : base(dataSource, argumentValue) + { + Table = DataSource.DatabaseMetadata.GetTableOrView(tableName); + } - /// - /// Gets the data source. - /// - /// The data source. - public new OleDbSqlServerDataSourceBase DataSource - { - get { return (OleDbSqlServerDataSourceBase)base.DataSource; } - } + /// + /// Gets the data source. + /// + /// The data source. + public new OleDbSqlServerDataSourceBase DataSource + { + get { return (OleDbSqlServerDataSourceBase)base.DataSource; } + } - /// - /// Gets the table metadata. - /// - /// The metadata. - public SqlServerTableOrViewMetadata Table { get; } + /// + /// Gets the table metadata. + /// + /// The metadata. + public SqlServerTableOrViewMetadata Table { get; } - /// - /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. - /// - /// - protected override TableOrViewMetadata OnGetTable() => Table; - } -} + /// + /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. + /// + /// + protected override TableOrViewMetadata OnGetTable() => Table; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerProcedureCall.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerProcedureCall.cs index bf39dffe0..4a08e5d87 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerProcedureCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerProcedureCall.cs @@ -1,96 +1,91 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Data; +using System.Collections.Immutable; using System.Data.OleDb; -using System.Linq; using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerProcedureCall. +/// +internal sealed class OleDbSqlServerProcedureCall : ProcedureDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly StoredProcedureMetadata m_Procedure; + /// - /// Class OleDbSqlServerProcedureCall. + /// Initializes a new instance of the class. /// - internal sealed class OleDbSqlServerProcedureCall : ProcedureDbCommandBuilder + /// The data source. + /// Name of the procedure. + /// The argument value. + internal OleDbSqlServerProcedureCall(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName procedureName, object? argumentValue = null) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly StoredProcedureMetadata m_Procedure; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the procedure. - /// The argument value. - internal OleDbSqlServerProcedureCall(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName procedureName, object? argumentValue = null) : base(dataSource) - { - if (procedureName == SqlServerObjectName.Empty) - throw new ArgumentException($"{nameof(procedureName)} is empty", nameof(procedureName)); + if (procedureName == SqlServerObjectName.Empty) + throw new ArgumentException($"{nameof(procedureName)} is empty", nameof(procedureName)); - m_ArgumentValue = argumentValue; - m_Procedure = DataSource.DatabaseMetadata.GetStoredProcedure(procedureName); - } - - /// - /// Gets the data source. - /// - /// The data source. - public new OleDbSqlServerDataSourceBase DataSource - { - get { return (OleDbSqlServerDataSourceBase)base.DataSource; } - } + m_ArgumentValue = argumentValue; + m_Procedure = DataSource.DatabaseMetadata.GetStoredProcedure(procedureName); + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Gets the data source. + /// + /// The data source. + public new OleDbSqlServerDataSourceBase DataSource + { + get { return (OleDbSqlServerDataSourceBase)base.DataSource; } + } - List parameters; + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (m_ArgumentValue is IEnumerable) - { - parameters = ((IEnumerable)m_ArgumentValue).ToList(); - } - else - { - var sqlBuilder = m_Procedure.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, m_ArgumentValue); - parameters = sqlBuilder.GetParameters(); - } + List parameters; - return new OleDbCommandExecutionToken(DataSource, m_Procedure.Name.ToString(), m_Procedure.Name.ToQuotedString(), parameters, CommandType.StoredProcedure); + if (m_ArgumentValue is IEnumerable) + { + parameters = ((IEnumerable)m_ArgumentValue).ToList(); } - - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + else { - return null; + var sqlBuilder = m_Procedure.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, m_ArgumentValue); + parameters = sqlBuilder.GetParameters(); } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; + return new OleDbCommandExecutionToken(DataSource, m_Procedure.Name.ToString(), m_Procedure.Name.ToQuotedString(), parameters, CommandType.StoredProcedure); } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return null; + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerScalarFunction.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerScalarFunction.cs index 26226092a..230a3418d 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerScalarFunction.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerScalarFunction.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.Immutable; using System.Data.OleDb; using System.Text; using Tortuga.Chain.CommandBuilders; @@ -8,87 +6,86 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Use for scalar functions. +/// +/// +internal class OleDbSqlServerScalarFunction : ScalarDbCommandBuilder { + readonly ScalarFunctionMetadata m_Function; + readonly object? m_FunctionArgumentValue; + /// - /// Use for scalar functions. + /// Initializes a new instance of the class. /// - /// - internal class OleDbSqlServerScalarFunction : ScalarDbCommandBuilder + /// The data source. + /// Name of the scalar function. + /// The function argument. + public OleDbSqlServerScalarFunction(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName scalarFunctionName, object? functionArgumentValue) : base(dataSource) { - readonly ScalarFunctionMetadata m_Function; - readonly object? m_FunctionArgumentValue; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the scalar function. - /// The function argument. - public OleDbSqlServerScalarFunction(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName scalarFunctionName, object? functionArgumentValue) : base(dataSource) - { - m_Function = dataSource.DatabaseMetadata.GetScalarFunction(scalarFunctionName); - m_FunctionArgumentValue = functionArgumentValue; - } - - /// - /// Gets the data source. - /// - /// The data source. - public new OleDbSqlServerDataSourceBase DataSource - { - get { return (OleDbSqlServerDataSourceBase)base.DataSource; } - } + m_Function = dataSource.DatabaseMetadata.GetScalarFunction(scalarFunctionName); + m_FunctionArgumentValue = functionArgumentValue; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Gets the data source. + /// + /// The data source. + public new OleDbSqlServerDataSourceBase DataSource + { + get { return (OleDbSqlServerDataSourceBase)base.DataSource; } + } - var sqlBuilder = m_Function.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (m_FunctionArgumentValue != null) - sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); + var sqlBuilder = m_Function.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); - var sql = new StringBuilder(); - sqlBuilder.BuildAnonymousFromFunctionClause(sql, $"SELECT {m_Function.Name.ToQuotedString()} (", " )"); - sql.Append(";"); + if (m_FunctionArgumentValue != null) + sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); - List parameters; - parameters = sqlBuilder.GetParameters(); + var sql = new StringBuilder(); + sqlBuilder.BuildAnonymousFromFunctionClause(sql, $"SELECT {m_Function.Name.ToQuotedString()} (", " )"); + sql.Append(";"); - return new OleDbCommandExecutionToken(DataSource, "Query Function " + m_Function.Name, sql.ToString(), parameters); - } + List parameters; + parameters = sqlBuilder.GetParameters(); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// ColumnMetadata. - /// Always returns null since this command builder has no columns - public override ColumnMetadata? TryGetColumn(string columnName) - { - return null; - } + return new OleDbCommandExecutionToken(DataSource, "Query Function " + m_Function.Name, sql.ToString(), parameters); + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// ColumnMetadata. + /// Always returns null since this command builder has no columns + public override ColumnMetadata? TryGetColumn(string columnName) + { + return null; } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerSqlCall.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerSqlCall.cs index 6ab62c42f..21ef48d97 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerSqlCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerSqlCall.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Data.OleDb; using Tortuga.Chain.CommandBuilders; @@ -7,64 +5,63 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerSqlCall. +/// +internal sealed class OleDbSqlServerSqlCall : MultipleTableDbCommandBuilder { - /// - /// Class OleDbSqlServerSqlCall. - /// - internal sealed class OleDbSqlServerSqlCall : MultipleTableDbCommandBuilder - { - readonly object? m_ArgumentValue; - readonly string m_SqlStatement; + readonly object? m_ArgumentValue; + readonly string m_SqlStatement; - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The SQL statement. - /// The argument value. - /// sqlStatement is null or empty.;sqlStatement - public OleDbSqlServerSqlCall(OleDbSqlServerDataSourceBase dataSource, string sqlStatement, object? argumentValue) : base(dataSource) - { - if (string.IsNullOrEmpty(sqlStatement)) - throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// The SQL statement. + /// The argument value. + /// sqlStatement is null or empty.;sqlStatement + public OleDbSqlServerSqlCall(OleDbSqlServerDataSourceBase dataSource, string sqlStatement, object? argumentValue) : base(dataSource) + { + if (string.IsNullOrEmpty(sqlStatement)) + throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); - m_SqlStatement = sqlStatement; - m_ArgumentValue = argumentValue; - } + m_SqlStatement = sqlStatement; + m_ArgumentValue = argumentValue; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - return new OleDbCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + return new OleDbCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) - { - return null; - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return null; + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableFunction.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableFunction.cs index 49b6e810b..35f0053ae 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableFunction.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableFunction.cs @@ -1,319 +1,319 @@ -using System; -using System.Collections.Generic; -using System.Data.OleDb; -using System.Linq; +using System.Data.OleDb; using System.Text; using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Use for table-valued functions. +/// +/// +internal class OleDbSqlServerTableFunction : TableDbCommandBuilder { + readonly object? m_FunctionArgumentValue; + readonly TableFunctionMetadata m_Table; + object? m_ArgumentValue; + FilterOptions m_FilterOptions; + object? m_FilterValue; + SqlServerLimitOption m_LimitOptions; + int? m_Seed; + string? m_SelectClause; + int? m_Skip; + IEnumerable m_SortExpressions = Enumerable.Empty(); + int? m_Take; + string? m_WhereClause; + /// - /// Use for table-valued functions. + /// Initializes a new instance of the class. /// - /// - internal class OleDbSqlServerTableFunction : TableDbCommandBuilder + /// The data source. + /// Name of the table function. + /// The function argument. + public OleDbSqlServerTableFunction(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableFunctionName, object? functionArgumentValue) : base(dataSource) { - readonly object? m_FunctionArgumentValue; - readonly TableFunctionMetadata m_Table; - object? m_ArgumentValue; - FilterOptions m_FilterOptions; - object? m_FilterValue; - SqlServerLimitOption m_LimitOptions; - int? m_Seed; - string? m_SelectClause; - int? m_Skip; - IEnumerable m_SortExpressions = Enumerable.Empty(); - int? m_Take; - string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table function. - /// The function argument. - public OleDbSqlServerTableFunction(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableFunctionName, object? functionArgumentValue) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableFunction(tableFunctionName); - m_FunctionArgumentValue = functionArgumentValue; - } + m_Table = dataSource.DatabaseMetadata.GetTableFunction(tableFunctionName); + m_FunctionArgumentValue = functionArgumentValue; + } - /// - /// Gets the data source. - /// - /// The data source. - public new OleDbSqlServerDataSourceBase DataSource - { - get { return (OleDbSqlServerDataSourceBase)base.DataSource; } - } + /// + /// Gets the data source. + /// + /// The data source. + public new OleDbSqlServerDataSourceBase DataSource + { + get { return (OleDbSqlServerDataSourceBase)base.DataSource; } + } - /// - /// Returns the row count using a SELECT Count(*) style query. - /// - /// - public override ILink AsCount() + /// + /// Returns the row count using a SELECT Count(*) style query. + /// + /// + public override ILink AsCount() + { + m_SelectClause = "COUNT_BIG(*)"; + return ToInt64(); + } + + /// + /// Returns the row count for a given column. SELECT Count(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT(DISTINCT columnName). + /// + public override ILink AsCount(string columnName, bool distinct = false) + { + var column = m_Table.Columns[columnName]; + if (distinct) + m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; + else + m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; + + return ToInt64(); + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); + + if (m_FunctionArgumentValue != null) + sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); + if (m_SelectClause == null) { - m_SelectClause = "COUNT_BIG(*)"; - return ToInt64(); + var desired = materializer.DesiredColumns(); + if (desired == Materializer.AutoSelectDesiredColumns) + desired = Materializer.AllColumns; + sqlBuilder.ApplyDesiredColumns(desired); } - /// - /// Returns the row count for a given column. SELECT Count(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT(DISTINCT columnName). - /// - public override ILink AsCount(string columnName, bool distinct = false) - { - var column = m_Table.Columns[columnName]; - if (distinct) - m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; - else - m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; + //Support check + if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) + throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); + if (m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) + throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions} with table-valued functions"); + if (m_Seed.HasValue) + throw new NotSupportedException($"SQL Server does not setting a random seed for table-valued functions"); - return ToInt64(); - } + //Validation + if (m_Skip < 0) + throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); - - if (m_FunctionArgumentValue != null) - sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); - if (m_SelectClause == null) - { - var desired = materializer.DesiredColumns(); - if (desired == Materializer.AutoSelectDesiredColumns) - desired = Materializer.AllColumns; - sqlBuilder.ApplyDesiredColumns(desired); - } - - //Support check - if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) - throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); - if (m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) - throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions} with table-valued functions"); - if (m_Seed.HasValue) - throw new NotSupportedException($"SQL Server does not setting a random seed for table-valued functions"); - - //Validation - if (m_Skip < 0) - throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); - - if (m_Skip > 0 && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); - - if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) - throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); - - if (m_Take <= 0) - throw new InvalidOperationException($"Cannot take {m_Take} rows"); - - if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); - - //SQL Generation - List parameters; - var sql = new StringBuilder(); - - string? topClause = null; - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - if (!m_SortExpressions.Any()) - topClause = $"TOP ({m_Take}) "; - break; - - case SqlServerLimitOption.Percentage: - topClause = $"TOP ({m_Take}) PERCENT "; - break; - - case SqlServerLimitOption.PercentageWithTies: - topClause = $"TOP ({m_Take}) PERCENT WITH TIES "; - break; - - case SqlServerLimitOption.RowsWithTies: - topClause = $"TOP ({m_Take}) WITH TIES "; - break; - } - - if (m_SelectClause != null) - sql.Append($"SELECT {topClause} {m_SelectClause} "); - else - sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); - - sqlBuilder.BuildAnonymousFromFunctionClause(sql, $" FROM {m_Table.Name.ToQuotedString()} (", " ) "); - - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions)); - sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " WHERE ", DataSource, null); - parameters = sqlBuilder.GetParameters(); - } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); - - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - - if (m_SortExpressions.Any()) - { - sql.Append(" OFFSET @offset_row_count_expression ROWS "); - parameters.Add(new OleDbParameter("@offset_row_count_expression", m_Skip ?? 0)); - - if (m_Take.HasValue) - { - sql.Append(" FETCH NEXT @fetch_row_count_expression ROWS ONLY"); - parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); - } - } - //else - //{ - // parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); - //} - break; + if (m_Skip > 0 && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); - case SqlServerLimitOption.Percentage: - case SqlServerLimitOption.PercentageWithTies: - case SqlServerLimitOption.RowsWithTies: - break; - } + if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) + throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); - sql.Append(";"); + if (m_Take <= 0) + throw new InvalidOperationException($"Cannot take {m_Take} rows"); - return new OleDbCommandExecutionToken(DataSource, "Query Function " + m_Table.Name, sql.ToString(), parameters); - } + if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) - { - return m_Table.Columns.TryGetColumn(columnName); - } + //SQL Generation + List parameters; + var sql = new StringBuilder(); - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<OleDbCommand, OleDbParameter, SqlServerLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + string? topClause = null; + switch (m_LimitOptions) { - m_FilterValue = filterValue; - m_WhereClause = null; - m_ArgumentValue = null; - m_FilterOptions = filterOptions; - return this; + case SqlServerLimitOption.Rows: + if (!m_SortExpressions.Any()) + topClause = $"TOP ({m_Take}) "; + break; + + case SqlServerLimitOption.Percentage: + topClause = $"TOP ({m_Take}) PERCENT "; + break; + + case SqlServerLimitOption.PercentageWithTies: + topClause = $"TOP ({m_Take}) PERCENT WITH TIES "; + break; + + case SqlServerLimitOption.RowsWithTies: + topClause = $"TOP ({m_Take}) WITH TIES "; + break; } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) - { - m_FilterValue = null; - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - return this; - } + if (m_SelectClause != null) + sql.Append($"SELECT {topClause} {m_SelectClause} "); + else + sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); + + sqlBuilder.BuildAnonymousFromFunctionClause(sql, $" FROM {m_Table.Name.ToQuotedString()} (", " ) "); - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + if (m_FilterValue != null) { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions)); + sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); - m_SortExpressions = sortExpressions; - return this; + parameters = sqlBuilder.GetParameters(); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); + sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = limitOptions; - return this; + sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " WHERE ", DataSource, null); + parameters = sqlBuilder.GetParameters(); } - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any() && StrictMode) + throw new InvalidOperationException("Limits were requested without a sort order. Use WithSorting to supply a sort order or disable strict mode."); + + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + + switch (m_LimitOptions) { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = (SqlServerLimitOption)limitOptions; - return this; + case SqlServerLimitOption.Rows: + + if (m_SortExpressions.Any()) + { + sql.Append(" OFFSET ? ROWS "); + parameters.Add(new OleDbParameter("@offset_row_count_expression", m_Skip ?? 0)); + + if (m_Take.HasValue) + { + sql.Append(" FETCH NEXT ? ROWS ONLY"); + parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); + } + } + //else + //{ + // parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); + //} + break; + + case SqlServerLimitOption.Percentage: + case SqlServerLimitOption.PercentageWithTies: + case SqlServerLimitOption.RowsWithTies: + break; } + + sql.Append(";"); + + return new OleDbCommandExecutionToken(DataSource, "Query Function " + m_Table.Name, sql.ToString(), parameters); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// TableDbCommandBuilder<OleDbCommand, OleDbParameter, SqlServerLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_FilterValue = filterValue; + m_WhereClause = null; + m_ArgumentValue = null; + m_FilterOptions = filterOptions; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + { + m_FilterValue = null; + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = limitOptions; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = (SqlServerLimitOption)limitOptions; + return this; + } + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableOrView.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableOrView.cs index e44be85bd..ac10220e9 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableOrView.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerTableOrView.cs @@ -1,344 +1,351 @@ -using System; -using System.Collections.Generic; -using System.Data.OleDb; +using System.Data.OleDb; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Text; using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// OleDbSqlServerTableOrView supports queries against tables and views. +/// +internal sealed partial class OleDbSqlServerTableOrView : TableDbCommandBuilder + where TObject : class { - /// - /// OleDbSqlServerTableOrView supports queries against tables and views. - /// - internal sealed partial class OleDbSqlServerTableOrView : TableDbCommandBuilder - where TObject : class - { - readonly TableOrViewMetadata m_Table; - object? m_ArgumentValue; - FilterOptions m_FilterOptions; - object? m_FilterValue; - SqlServerLimitOption m_LimitOptions; - int? m_Seed; - string? m_SelectClause; - int? m_Skip; - IEnumerable m_SortExpressions = Enumerable.Empty(); - int? m_Take; - string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// - public OleDbSqlServerTableOrView(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None) : base(dataSource) - { - if (tableOrViewName == SqlServerObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - } - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The where clause. - /// The argument value. - public OleDbSqlServerTableOrView(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, string? whereClause, object? argumentValue) : base(dataSource) - { - if (tableOrViewName == SqlServerObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - - m_ArgumentValue = argumentValue; - m_WhereClause = whereClause; - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - } - - /// - /// Gets the data source. - /// - /// The data source. - public new OleDbSqlServerDataSourceBase DataSource - { - get { return (OleDbSqlServerDataSourceBase)base.DataSource; } - } - - /// - /// Returns the row count using a SELECT COUNT_BIG(*) style query. - /// - /// - public override ILink AsCount() - { - m_SelectClause = "COUNT_BIG(*)"; - return ToInt64(); - } - - /// - /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). - /// - public override ILink AsCount(string columnName, bool distinct = false) - { - var column = m_Table.Columns[columnName]; - if (distinct) - m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; - else - m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; - - return ToInt64(); - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); - - if (m_SelectClause == null) - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - //Support check - if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) - throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); - - //Validation - if (m_Skip < 0) - throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); - - if (m_Skip > 0 && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); - - if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) - throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); - - if (m_Take <= 0) - throw new InvalidOperationException($"Cannot take {m_Take} rows"); - - if ((m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) && m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform random sampling when sorting."); - - if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); - - //SQL Generation - var parameters = new List(); - var sql = new StringBuilder(); - - string? topClause = null; - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - if (!m_SortExpressions.Any()) - topClause = $"TOP ({m_Take}) "; - break; - - case SqlServerLimitOption.Percentage: - topClause = $"TOP ({m_Take}) PERCENT "; - break; - - case SqlServerLimitOption.PercentageWithTies: - topClause = $"TOP ({m_Take}) PERCENT WITH TIES "; - break; - - case SqlServerLimitOption.RowsWithTies: - topClause = $"TOP ({m_Take}) WITH TIES "; - break; - } - - if (m_SelectClause != null) - sql.Append($"SELECT {topClause} {m_SelectClause} "); - else - sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); - - sql.Append(" FROM " + m_Table.Name.ToQuotedString()); - - switch (m_LimitOptions) - { - case SqlServerLimitOption.TableSampleSystemRows: - sql.Append($" TABLESAMPLE SYSTEM ({m_Take} ROWS) "); - if (m_Seed.HasValue) - sql.Append($"REPEATABLE ({m_Seed}) "); - break; - - case SqlServerLimitOption.TableSampleSystemPercentage: - sql.Append($" TABLESAMPLE SYSTEM ({m_Take} PERCENT) "); - if (m_Seed.HasValue) - sql.Append($"REPEATABLE ({m_Seed}) "); - break; - } - - if (m_FilterValue != null) - { - sql.Append(" WHERE (" + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions) + ")"); - sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters.AddRange(sqlBuilder.GetParameters()); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE (" + m_WhereClause + ")"); - sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " WHERE ", DataSource, null); - parameters.AddRange(sqlBuilder.GetParameters()); - } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); - - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - - if (m_SortExpressions.Any()) - { - sql.Append(" OFFSET ? ROWS "); - parameters.Add(new OleDbParameter("@offset_row_count_expression", m_Skip ?? 0)); - - if (m_Take.HasValue) - { - sql.Append(" FETCH NEXT ? ROWS ONLY"); - parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); - } - } - //else - //{ - // parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); - //} - break; - - case SqlServerLimitOption.Percentage: - case SqlServerLimitOption.PercentageWithTies: - case SqlServerLimitOption.RowsWithTies: - break; - } - - sql.Append(";"); - - return new OleDbCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); - } - - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) - { - return m_Table.Columns.TryGetColumn(columnName); - } - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<OleDbCommand, OleDbParameter, SqlServerLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) - { - m_FilterValue = filterValue; - m_WhereClause = null; - m_ArgumentValue = null; - m_FilterOptions = filterOptions; - return this; - } - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) - { - m_FilterValue = null; - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - return this; - } - - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); - - m_SortExpressions = sortExpressions; - return this; - } - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) - { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = limitOptions; - return this; - } - - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) - { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = (SqlServerLimitOption)limitOptions; - return this; - } - } -} + readonly TableOrViewMetadata m_Table; + object? m_ArgumentValue; + FilterOptions m_FilterOptions; + object? m_FilterValue; + SqlServerLimitOption m_LimitOptions; + int? m_Seed; + string? m_SelectClause; + int? m_Skip; + IEnumerable m_SortExpressions = Enumerable.Empty(); + int? m_Take; + string? m_WhereClause; + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table or view. + /// The filter value. + /// The filter options. + /// + public OleDbSqlServerTableOrView(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None) : base(dataSource) + { + if (tableOrViewName == SqlServerObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + } + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table or view. + /// The where clause. + /// The argument value. + public OleDbSqlServerTableOrView(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, string? whereClause, object? argumentValue) : base(dataSource) + { + if (tableOrViewName == SqlServerObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + + m_ArgumentValue = argumentValue; + m_WhereClause = whereClause; + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + } + + /// + /// Gets the data source. + /// + /// The data source. + public new OleDbSqlServerDataSourceBase DataSource + { + get { return (OleDbSqlServerDataSourceBase)base.DataSource; } + } + + /// + /// Returns the row count using a SELECT COUNT_BIG(*) style query. + /// + /// + public override ILink AsCount() + { + m_SelectClause = "COUNT_BIG(*)"; + return ToInt64(); + } + + /// + /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). + /// + public override ILink AsCount(string columnName, bool distinct = false) + { + var column = m_Table.Columns[columnName]; + if (distinct) + m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; + else + m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; + + return ToInt64(); + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); + + if (m_SelectClause == null) + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + //Support check + if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) + throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); + + //Validation + if (m_Skip < 0) + throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); + + if (m_Skip > 0 && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); + + if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) + throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); + + if (m_Take <= 0) + throw new InvalidOperationException($"Cannot take {m_Take} rows"); + + if ((m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) && m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform random sampling when sorting."); + + if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); + + //SQL Generation + var parameters = new List(); + var sql = new StringBuilder(); + + string? topClause = null; + switch (m_LimitOptions) + { + case SqlServerLimitOption.Rows: + if (!m_SortExpressions.Any()) + topClause = $"TOP ({m_Take}) "; + break; + + case SqlServerLimitOption.Percentage: + topClause = $"TOP ({m_Take}) PERCENT "; + break; + + case SqlServerLimitOption.PercentageWithTies: + topClause = $"TOP ({m_Take}) PERCENT WITH TIES "; + break; + + case SqlServerLimitOption.RowsWithTies: + topClause = $"TOP ({m_Take}) WITH TIES "; + break; + } + + if (m_SelectClause != null) + sql.Append($"SELECT {topClause} {m_SelectClause} "); + else + sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); + + sql.Append(" FROM " + m_Table.Name.ToQuotedString()); + + switch (m_LimitOptions) + { + case SqlServerLimitOption.TableSampleSystemRows: + sql.Append($" TABLESAMPLE SYSTEM ({m_Take} ROWS) "); + if (m_Seed.HasValue) + sql.Append($"REPEATABLE ({m_Seed}) "); + break; + + case SqlServerLimitOption.TableSampleSystemPercentage: + sql.Append($" TABLESAMPLE SYSTEM ({m_Take} PERCENT) "); + if (m_Seed.HasValue) + sql.Append($"REPEATABLE ({m_Seed}) "); + break; + } + + if (m_FilterValue != null) + { + sql.Append(" WHERE (" + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions) + ")"); + sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); + + parameters.AddRange(sqlBuilder.GetParameters()); + } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE (" + m_WhereClause + ")"); + sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " AND (", DataSource, ") "); + + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else + { + sqlBuilder.BuildAnonymousSoftDeleteClause(sql, " WHERE ", DataSource, null); + parameters.AddRange(sqlBuilder.GetParameters()); + } + + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any()) + { + if (m_Table.HasPrimaryKey) + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_Table.PrimaryKeyColumns.Select(x => new SortExpression(x.SqlName)), null); + else if (StrictMode) + throw new InvalidOperationException("Limits were requested, but no primary keys were detected. Use WithSorting to supply a sort order or disable strict mode."); + } + else + { + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + } + + switch (m_LimitOptions) + { + case SqlServerLimitOption.Rows: + + if (m_SortExpressions.Any()) + { + sql.Append(" OFFSET ? ROWS "); + parameters.Add(new OleDbParameter("@offset_row_count_expression", m_Skip ?? 0)); + + if (m_Take.HasValue) + { + sql.Append(" FETCH NEXT ? ROWS ONLY"); + parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); + } + } + //else + //{ + // parameters.Add(new OleDbParameter("@fetch_row_count_expression", m_Take)); + //} + break; + + case SqlServerLimitOption.Percentage: + case SqlServerLimitOption.PercentageWithTies: + case SqlServerLimitOption.RowsWithTies: + break; + } + + sql.Append(";"); + + return new OleDbCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// TableDbCommandBuilder<OleDbCommand, OleDbParameter, SqlServerLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_FilterValue = filterValue; + m_WhereClause = null; + m_ArgumentValue = null; + m_FilterOptions = filterOptions; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + { + m_FilterValue = null; + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = limitOptions; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = (SqlServerLimitOption)limitOptions; + return this; + } + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; + } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateObject.cs index 67e50ae9a..f59ea7884 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateObject.cs @@ -1,71 +1,69 @@ -using System; -using System.Data.OleDb; +using System.Data.OleDb; using System.Text; using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerUpdateObject. +/// +internal sealed class OleDbSqlServerUpdateObject : OleDbSqlServerObjectCommand + where TArgument : class { + readonly UpdateOptions m_Options; + /// - /// Class OleDbSqlServerUpdateObject. + /// Initializes a new instance of the class. /// - internal sealed class OleDbSqlServerUpdateObject : OleDbSqlServerObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public OleDbSqlServerUpdateObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpdateOptions options) : base(dataSource, tableName, argumentValue) { - readonly UpdateOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public OleDbSqlServerUpdateObject(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpdateOptions options) : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) - throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); + if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) + throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; + var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; + var sql = new StringBuilder(); + string? header; + string? intoClause; + string? footer; - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); + sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - sql.Append(header); - sql.Append($"UPDATE {Table.Name.ToQuotedString()}"); - sqlBuilder.BuildAnonymousSetClause(sql, " SET ", null, null); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); - sqlBuilder.BuildAnonymousWhereClause(sql, " WHERE ", null, false); //second pass parameters - sql.Append(";"); - sql.Append(footer); + sql.Append(header); + sql.Append($"UPDATE {Table.Name.ToQuotedString()}"); + sqlBuilder.BuildAnonymousSetClause(sql, " SET ", null, null); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); + sqlBuilder.BuildAnonymousWhereClause(sql, " WHERE ", null, false); //second pass parameters + sql.Append(";"); + sql.Append(footer); - return new OleDbCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckUpdateRowCount(m_Options); - } + return new OleDbCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckUpdateRowCount(m_Options); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateSet.cs index 3b5fb55d5..d627bcc52 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/CommandBuilders/OleDbSqlServerUpdateSet.cs @@ -5,229 +5,228 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class OleDbSqlServerUpdateSet. +/// +internal sealed class OleDbSqlServerUpdateSet : UpdateSetDbCommandBuilder { + readonly int? m_ExpectedRowCount; + readonly object? m_NewValues; + readonly UpdateOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly SqlServerTableOrViewMetadata m_Table; + readonly object? m_UpdateArgumentValue; + readonly string? m_UpdateExpression; + FilterOptions m_FilterOptions; + object? m_FilterValue; + object? m_WhereArgumentValue; + string? m_WhereClause; + /// - /// Class OleDbSqlServerUpdateSet. + /// Initializes a new instance of the class. /// - internal sealed class OleDbSqlServerUpdateSet : UpdateSetDbCommandBuilder + /// The data source. + /// Name of the table. + /// The new values. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public OleDbSqlServerUpdateSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, string? whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) { - readonly int? m_ExpectedRowCount; - readonly object? m_NewValues; - readonly UpdateOptions m_Options; - readonly IEnumerable? m_Parameters; - readonly SqlServerTableOrViewMetadata m_Table; - readonly object? m_UpdateArgumentValue; - readonly string? m_UpdateExpression; - FilterOptions m_FilterOptions; - object? m_FilterValue; - object? m_WhereArgumentValue; - string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public OleDbSqlServerUpdateSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, string? whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_WhereClause = whereClause; - m_ExpectedRowCount = expectedRowCount; - m_Options = options; - m_Parameters = parameters; - } + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_WhereClause = whereClause; + m_ExpectedRowCount = expectedRowCount; + m_Options = options; + m_Parameters = parameters; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The options. - /// Cannot use Key attributes with this operation. - public OleDbSqlServerUpdateSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The new values. + /// The options. + /// Cannot use Key attributes with this operation. + public OleDbSqlServerUpdateSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_Options = options; - } + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_Options = options; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The update expression. - /// The update argument value. - /// The options. - /// Cannot use Key attributes with this operation. - public OleDbSqlServerUpdateSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string? updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The update expression. + /// The update argument value. + /// The options. + /// Cannot use Key attributes with this operation. + public OleDbSqlServerUpdateSet(OleDbSqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string? updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_UpdateExpression = updateExpression; - m_Options = options; - m_UpdateArgumentValue = updateArgumentValue; - } + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_UpdateExpression = updateExpression; + m_Options = options; + m_UpdateArgumentValue = updateArgumentValue; + } - /// - /// Applies this command to all rows. - /// - /// - public override UpdateSetDbCommandBuilder All() - { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; - } + /// + /// Applies this command to all rows. + /// + /// + public override UpdateSetDbCommandBuilder All() + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, false); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; - - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; - - sqlBuilder.UseTableVariable(m_Table, out header, out intoClause, out footer); - - sql.Append(header); - sql.Append($"UPDATE {m_Table.Name.ToQuotedString()}"); - var parameters = new List(); - - if (m_UpdateExpression == null) - { - sqlBuilder.BuildAnonymousSetClause(sql, " SET ", null, null); - } - else - { - sql.Append(" SET " + m_UpdateExpression); - parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); - } - - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); - - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions, true)); - - parameters.AddRange(sqlBuilder.GetParameters()); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - - parameters.AddRange(sqlBuilder.GetParameters()); - parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); - } - else - { - parameters.AddRange(sqlBuilder.GetParameters()); - } - sql.Append(";"); - sql.Append(footer); - - if (m_Parameters != null) - parameters.AddRange(m_Parameters); - - return new OleDbCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); - } + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, false); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; + + var sql = new StringBuilder(); + string? header; + string? intoClause; + string? footer; + + sqlBuilder.UseTableVariable(m_Table, out header, out intoClause, out footer); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + sql.Append(header); + sql.Append($"UPDATE {m_Table.Name.ToQuotedString()}"); + var parameters = new List(); + + if (m_UpdateExpression == null) { - return m_Table.Columns.TryGetColumn(columnName); + sqlBuilder.BuildAnonymousSetClause(sql, " SET ", null, null); } - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + else { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - return this; + sql.Append(" SET " + m_UpdateExpression); + parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); + + if (m_FilterValue != null) { - m_WhereClause = whereClause; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + sql.Append(" WHERE " + sqlBuilder.ApplyAnonymousFilterValue(m_FilterValue, m_FilterOptions, true)); + + parameters.AddRange(sqlBuilder.GetParameters()); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + parameters.AddRange(sqlBuilder.GetParameters()); + parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); + } + else { - m_WhereClause = whereClause; - m_WhereArgumentValue = argumentValue; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + parameters.AddRange(sqlBuilder.GetParameters()); } + sql.Append(";"); + sql.Append(footer); + + if (m_Parameters != null) + parameters.AddRange(m_Parameters); + + return new OleDbCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = argumentValue; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.CommandBuilders.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.CommandBuilders.cs index ea3b727a8..9c210f238 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.CommandBuilders.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.CommandBuilders.cs @@ -2,15 +2,12 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.SqlServer.CommandBuilders; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +partial class OleDbSqlServerDataSourceBase { - partial class OleDbSqlServerDataSourceBase + ObjectDbCommandBuilder OnInsertOrUpdateObject(SqlServerObjectName tableName, TArgument argumentValue, UpsertOptions options) where TArgument : class { - - ObjectDbCommandBuilder OnInsertOrUpdateObject(SqlServerObjectName tableName, TArgument argumentValue, UpsertOptions options) where TArgument : class - { - return new OleDbSqlServerInsertOrUpdateObject(this, tableName, argumentValue, options); - } - + return new OleDbSqlServerInsertOrUpdateObject(this, tableName, argumentValue, options); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.Traits.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.Traits.cs index bb4a15788..fa2bbcb0e 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerDataSourceBase.Traits.cs @@ -9,8 +9,8 @@ namespace Tortuga.Chain.SqlServer; -[UseTrait(typeof(SupportsDeleteAllTrait))] -[UseTrait(typeof(SupportsTruncateTrait))] +[UseTrait(typeof(SupportsDeleteAllTrait))] +[UseTrait(typeof(SupportsTruncateTrait))] [UseTrait(typeof(SupportsSqlQueriesTrait))] [UseTrait(typeof(SupportsDeleteByKeyListTrait))] [UseTrait(typeof(SupportsDeleteTrait))] @@ -25,6 +25,7 @@ namespace Tortuga.Chain.SqlServer; [UseTrait(typeof(SupportsScalarFunctionTrait))] [UseTrait(typeof(SupportsProcedureTrait))] [UseTrait(typeof(SupportsTableFunctionTrait))] +[UseTrait(typeof(SupportsGetByColumnListTrait))] partial class OleDbSqlServerDataSourceBase : ICrudDataSource, IAdvancedCrudDataSource { DatabaseMetadataCache ICommandHelper.DatabaseMetadata => DatabaseMetadata; @@ -93,10 +94,9 @@ TableDbCommandBuilder(this, tableOrViewName, filterValue, filterOptions); } - SingleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class { - string where = keyColumn.SqlName + " = ?"; var parameters = new List(); @@ -127,7 +127,6 @@ MultipleRowDbCommandBuilder IGetByKeyHelper< } return new MultipleRowDbCommandBuilder(new OleDbSqlServerTableOrView(this, tableName, where, parameters)); - } ObjectDbCommandBuilder IInsertHelper.OnInsertObject(AbstractObjectName tableName, TArgument argumentValue, InsertOptions options) @@ -165,7 +164,6 @@ MultipleRowDbCommandBuilder IUpdateDeleteByK } return new OleDbSqlServerUpdateSet(this, tableName, newValues, where, parameters, parameters.Count, options); - } ObjectDbCommandBuilder IUpdateDeleteHelper.OnUpdateObject(AbstractObjectName tableName, TArgument argumentValue, UpdateOptions options) @@ -217,4 +215,4 @@ private partial TableDbCommandBuilder +/// Class SqlServerDataSourceBase. +/// +public abstract partial class OleDbSqlServerDataSourceBase : DataSource { /// - /// Class SqlServerDataSourceBase. + /// Initializes a new instance of the class. /// - public abstract partial class OleDbSqlServerDataSourceBase : DataSource + /// Optional settings value. + protected OleDbSqlServerDataSourceBase(SqlServerDataSourceSettings? settings) : base(settings) { - /// - /// Initializes a new instance of the class. - /// - /// Optional settings value. - protected OleDbSqlServerDataSourceBase(SqlServerDataSourceSettings? settings) : base(settings) - { - } - - /// - /// Gets the database metadata. - /// - /// The database metadata. - public abstract new OleDbSqlServerMetadataCache DatabaseMetadata { get; } + } - /// - /// Called when Database.DatabaseMetadata is invoked. - /// - /// - protected override IDatabaseMetadataCache OnGetDatabaseMetadata() => DatabaseMetadata; + /// + /// Gets the database metadata. + /// + /// The database metadata. + public abstract new OleDbSqlServerMetadataCache DatabaseMetadata { get; } - } + /// + /// Called when Database.DatabaseMetadata is invoked. + /// + /// + protected override IDatabaseMetadataCache OnGetDatabaseMetadata() => DatabaseMetadata; } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerEffectiveSettings.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerEffectiveSettings.cs index 6a3cbec6a..ec3939aec 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerEffectiveSettings.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerEffectiveSettings.cs @@ -1,104 +1,102 @@ using System.Data.OleDb; using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// This contains the connection options that are currently in effect. +/// +public class OleDbSqlServerEffectiveSettings { + int m_Options; + + internal OleDbSqlServerEffectiveSettings() + { + } + + /// + /// ANSI_NULL_DFLT_OFF. Alters the session's behavior not to use ANSI compatibility for nullability. New columns defined without explicit nullability do not allow nulls. + /// + public bool AnsiNullDefaultOff { get { return (m_Options & 2048) > 0; } } + + /// + /// ANSI_NULL_DFLT_ON. Alters the session's behavior to use ANSI compatibility for nullability. New columns defined without explicit nullability are defined to allow nulls. + /// + public bool AnsiNullDefaultOn { get { return (m_Options & 1024) > 0; } } + + /// + /// ANSI_NULLS. Controls NULL handling when using equality operators. + /// + public bool AnsiNulls { get { return (m_Options & 32) > 0; } } + + /// + /// ANSI_PADDING. Controls padding of fixed-length variables. + /// + public bool AnsiPadding { get { return (m_Options & 16) > 0; } } + + /// + /// ANSI_WARNINGS. Controls truncation and NULL in aggregate warnings. + /// + public bool AnsiWarning { get { return (m_Options & 8) > 0; } } + + /// + /// ARITHABORT. Terminates a query when an overflow or divide-by-zero error occurs during query execution. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool ArithAbort { get { return (m_Options & 64) > 0; } } + + /// + /// ARITHIGNORE. Returns NULL when an overflow or divide-by-zero error occurs during a query. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool ArithIgnore { get { return (m_Options & 128) > 0; } } + + /// + /// CONCAT_NULL_YIELDS_NULL. Returns NULL when concatenating a NULL value with a string. + /// + public bool ConcatNullYieldsNull { get { return (m_Options & 4096) > 0; } } + + /// + /// CURSOR_CLOSE_ON_COMMIT. Controls behavior of cursors after a commit operation has been performed. + /// + public bool CursorCloseOnCommit { get { return (m_Options & 4) > 0; } } + + /// + /// DISABLE_DEF_CNST_CHK. Controls interim or deferred constraint checking. + /// + public bool DisableDeferredConstraintChecking { get { return (m_Options & 1) > 0; } } + + /// + /// NOCOUNT. Turns off the message returned at the end of each statement that states how many rows were affected. + /// + public bool NoCount { get { return (m_Options & 512) > 0; } } + + /// + /// NUMERIC_ROUNDABORT. Generates an error when a loss of precision occurs in an expression. + /// + public bool NumericRoundAbort { get { return (m_Options & 8192) > 0; } } + + /// + /// QUOTED_IDENTIFIER. Differentiates between single and double quotation marks when evaluating an expression. + /// + public bool QuotedIdentifier { get { return (m_Options & 256) > 0; } } + /// - /// This contains the connection options that are currently in effect. + /// XACT_ABORT. Rolls back a transaction if a Transact-SQL statement raises a run-time error. /// - public class OleDbSqlServerEffectiveSettings + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] + public bool XactAbort { get { return (m_Options & 16384) > 0; } } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + internal void Reload(OleDbConnection connection, OleDbTransaction? transaction) + { + using (var cmd = new OleDbCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) + m_Options = (int)cmd.ExecuteScalar()!; + } + + internal async Task ReloadAsync(OleDbConnection connection, OleDbTransaction? transaction) { - int m_Options; - - internal OleDbSqlServerEffectiveSettings() - { - } - - /// - /// ANSI_NULL_DFLT_OFF. Alters the session's behavior not to use ANSI compatibility for nullability. New columns defined without explicit nullability do not allow nulls. - /// - public bool AnsiNullDefaultOff { get { return (m_Options & 2048) > 0; } } - - /// - /// ANSI_NULL_DFLT_ON. Alters the session's behavior to use ANSI compatibility for nullability. New columns defined without explicit nullability are defined to allow nulls. - /// - public bool AnsiNullDefaultOn { get { return (m_Options & 1024) > 0; } } - - /// - /// ANSI_NULLS. Controls NULL handling when using equality operators. - /// - public bool AnsiNulls { get { return (m_Options & 32) > 0; } } - - /// - /// ANSI_PADDING. Controls padding of fixed-length variables. - /// - public bool AnsiPadding { get { return (m_Options & 16) > 0; } } - - /// - /// ANSI_WARNINGS. Controls truncation and NULL in aggregate warnings. - /// - public bool AnsiWarning { get { return (m_Options & 8) > 0; } } - - /// - /// ARITHABORT. Terminates a query when an overflow or divide-by-zero error occurs during query execution. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool ArithAbort { get { return (m_Options & 64) > 0; } } - - /// - /// ARITHIGNORE. Returns NULL when an overflow or divide-by-zero error occurs during a query. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool ArithIgnore { get { return (m_Options & 128) > 0; } } - - /// - /// CONCAT_NULL_YIELDS_NULL. Returns NULL when concatenating a NULL value with a string. - /// - public bool ConcatNullYieldsNull { get { return (m_Options & 4096) > 0; } } - - /// - /// CURSOR_CLOSE_ON_COMMIT. Controls behavior of cursors after a commit operation has been performed. - /// - public bool CursorCloseOnCommit { get { return (m_Options & 4) > 0; } } - - /// - /// DISABLE_DEF_CNST_CHK. Controls interim or deferred constraint checking. - /// - public bool DisableDeferredConstraintChecking { get { return (m_Options & 1) > 0; } } - - /// - /// NOCOUNT. Turns off the message returned at the end of each statement that states how many rows were affected. - /// - public bool NoCount { get { return (m_Options & 512) > 0; } } - - /// - /// NUMERIC_ROUNDABORT. Generates an error when a loss of precision occurs in an expression. - /// - public bool NumericRoundAbort { get { return (m_Options & 8192) > 0; } } - - /// - /// QUOTED_IDENTIFIER. Differentiates between single and double quotation marks when evaluating an expression. - /// - public bool QuotedIdentifier { get { return (m_Options & 256) > 0; } } - - /// - /// XACT_ABORT. Rolls back a transaction if a Transact-SQL statement raises a run-time error. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] - public bool XactAbort { get { return (m_Options & 16384) > 0; } } - - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - internal void Reload(OleDbConnection connection, OleDbTransaction? transaction) - { - using (var cmd = new OleDbCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) - m_Options = (int)cmd.ExecuteScalar()!; - } - - internal async Task ReloadAsync(OleDbConnection connection, OleDbTransaction? transaction) - { - using (var cmd = new OleDbCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) - m_Options = (int)(await cmd.ExecuteScalarAsync().ConfigureAwait(false))!; - } + using (var cmd = new OleDbCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) + m_Options = (int)(await cmd.ExecuteScalarAsync().ConfigureAwait(false))!; } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerMetadataCache.cs index a62703c03..0b9f75bb9 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerMetadataCache.cs @@ -3,93 +3,93 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class OleDbSqlServerMetadataCache. +/// +/// +public sealed partial class OleDbSqlServerMetadataCache { /// - /// Class OleDbSqlServerMetadataCache. + /// Initializes a new instance of the class. /// - /// - public sealed partial class OleDbSqlServerMetadataCache + /// The connection builder. + public OleDbSqlServerMetadataCache(OleDbConnectionStringBuilder connectionBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The connection builder. - public OleDbSqlServerMetadataCache(OleDbConnectionStringBuilder connectionBuilder) - { - m_ConnectionBuilder = connectionBuilder; - } + m_ConnectionBuilder = connectionBuilder; + } - /// - /// Returns the current database. - /// - /// - public string DatabaseName + /// + /// Returns the current database. + /// + /// + public string DatabaseName + { + get { - get + if (m_DatabaseName == null) { - if (m_DatabaseName == null) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new OleDbCommand("SELECT DB_NAME () AS DatabaseName", con)) { - con.Open(); - using (var cmd = new OleDbCommand("SELECT DB_NAME () AS DatabaseName", con)) - { - m_DatabaseName = (string)cmd.ExecuteScalar()!; - } + m_DatabaseName = (string)cmd.ExecuteScalar()!; } } - return m_DatabaseName; } + return m_DatabaseName; } + } - /// - /// Returns the user's default schema. - /// - /// - public string DefaultSchema + /// + /// Returns the user's default schema. + /// + /// + public string DefaultSchema + { + get { - get + if (m_DefaultSchema == null) { - if (m_DefaultSchema == null) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new OleDbCommand("SELECT SCHEMA_NAME () AS DefaultSchema", con)) { - con.Open(); - using (var cmd = new OleDbCommand("SELECT SCHEMA_NAME () AS DefaultSchema", con)) - { - m_DefaultSchema = (string)cmd.ExecuteScalar()!; - } + m_DefaultSchema = (string)cmd.ExecuteScalar()!; } } - return m_DefaultSchema; } + return m_DefaultSchema; } + } - /// - /// Gets a list of known, unsupported SQL type names that cannot be mapped to a OleDbType. - /// - /// Case-insensitive list of database-specific type names - /// This list is based on driver limitations. - public override ImmutableHashSet UnsupportedSqlTypeNames { get; } = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, new[] { "datetimeoffset", "geography", "geometry", "hierarchyid", "image", "sql_variant", "sysname", "xml" }); - - /// - /// Gets the detailed metadata for a table or view. - /// - /// Name of the table. - /// SqlServerTableOrViewMetadata<TDbType>. - public new SqlServerTableOrViewMetadata GetTableOrView(SqlServerObjectName tableName) - { - return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); - } + /// + /// Gets a list of known, unsupported SQL type names that cannot be mapped to a OleDbType. + /// + /// Case-insensitive list of database-specific type names + /// This list is based on driver limitations. + public override ImmutableHashSet UnsupportedSqlTypeNames { get; } = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, new[] { "datetimeoffset", "geography", "geometry", "hierarchyid", "image", "sql_variant", "sysname", "xml" }); - /// - /// Preloads the scalar functions. - /// - public void PreloadScalarFunctions() - { - const string TvfSql = - @"SELECT + /// + /// Gets the detailed metadata for a table or view. + /// + /// Name of the table. + /// SqlServerTableOrViewMetadata<TDbType>. + public new SqlServerTableOrViewMetadata GetTableOrView(SqlServerObjectName tableName) + { + return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); + } + + /// + /// Preloads the scalar functions. + /// + public void PreloadScalarFunctions() + { + const string TvfSql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId @@ -97,61 +97,61 @@ FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.type in ('FN')"; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(TvfSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetScalarFunction(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetScalarFunction(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads the stored procedures. - /// - public void PreloadStoredProcedures() - { - const string StoredProcedureSql = - @"SELECT + /// + /// Preloads the stored procedures. + /// + public void PreloadStoredProcedures() + { + const string StoredProcedureSql = + @"SELECT s.name AS SchemaName, sp.name AS Name FROM SYS.procedures sp INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id;"; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(StoredProcedureSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(StoredProcedureSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetStoredProcedure(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetStoredProcedure(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads the table value functions. - /// - public void PreloadTableFunctions() - { - const string TvfSql = - @"SELECT + /// + /// Preloads the table value functions. + /// + public void PreloadTableFunctions() + { + const string TvfSql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId @@ -159,141 +159,141 @@ FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.type in ('TF', 'IF', 'FT')"; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(TvfSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetTableFunction(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetTableFunction(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads metadata for all tables. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadTables() - { - const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; + /// + /// Preloads metadata for all tables. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadTables() + { + const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(tableList, con)) { - con.Open(); - using (var cmd = new OleDbCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetTableOrView(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetTableOrView(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads the user defined types. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadUserDefinedTableTypes() - { - const string tableList = @"SELECT s.name AS SchemaName, t.name AS Name FROM sys.types t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.is_user_defined = 1;"; + /// + /// Preloads the user defined types. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadUserDefinedTableTypes() + { + const string tableList = @"SELECT s.name AS SchemaName, t.name AS Name FROM sys.types t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.is_user_defined = 1;"; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(tableList, con)) { - con.Open(); - using (var cmd = new OleDbCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetUserDefinedTableType(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetUserDefinedTableType(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads metadata for all views. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadViews() - { - const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.views t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; + /// + /// Preloads metadata for all views. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadViews() + { + const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.views t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(tableList, con)) { - con.Open(); - using (var cmd = new OleDbCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetTableOrView(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetTableOrView(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Converts a value to a string suitable for use in a SQL statement. - /// - /// The value. - /// Optional database column type. - /// - public override string ValueToSqlValue(object value, OleDbType? dbType) + /// + /// Converts a value to a string suitable for use in a SQL statement. + /// + /// The value. + /// Optional database column type. + /// + public override string ValueToSqlValue(object value, OleDbType? dbType) + { + switch (value) { - switch (value) - { - case string s: + case string s: + { + switch (dbType) { - switch (dbType) - { - case OleDbType.Char: - case OleDbType.LongVarChar: - case OleDbType.VarChar: - return "'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; - - case OleDbType.WChar: - case OleDbType.BSTR: - case OleDbType.VarWChar: - case OleDbType.LongVarWChar: - return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; - - default: //Assume Unicode - return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; - } + case OleDbType.Char: + case OleDbType.LongVarChar: + case OleDbType.VarChar: + return "'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; + + case OleDbType.WChar: + case OleDbType.BSTR: + case OleDbType.VarWChar: + case OleDbType.LongVarWChar: + return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; + + default: //Assume Unicode + return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; } + } - default: - return base.ValueToSqlValue(value, dbType); - } + default: + return base.ValueToSqlValue(value, dbType); } + } - internal ScalarFunctionMetadata GetScalarFunctionInternal(SqlServerObjectName tableFunctionName) - { - const string sql = - @"SELECT s.name AS SchemaName, + internal ScalarFunctionMetadata GetScalarFunctionInternal(SqlServerObjectName tableFunctionName) + { + const string sql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId, COALESCE(t.name, t2.name) AS TypeName, @@ -302,61 +302,61 @@ internal ScalarFunctionMetadata GetScalarFunctio CONVERT(INT, COALESCE(p.precision, t.precision, t2.precision)) AS precision, CONVERT(INT, COALESCE(p.scale, t.scale, t2.scale)) AS scale - FROM sys.objects o - INNER JOIN sys.schemas s ON o.schema_id = s.schema_id - INNER JOIN sys.parameters p ON p.object_id = o.object_id AND p.parameter_id = 0 + FROM sys.objects o + INNER JOIN sys.schemas s ON o.schema_id = s.schema_id + INNER JOIN sys.parameters p ON p.object_id = o.object_id AND p.parameter_id = 0 LEFT JOIN sys.types t on p.system_type_id = t.user_type_id LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id - WHERE o.type IN ('FN') + WHERE o.type IN ('FN') AND s.name = ? AND o.name = ?;"; - string actualSchema; - string actualName; - int objectId; + string actualSchema; + string actualName; + int objectId; - string fullTypeName; - string typeName; - bool isNullable; - int? maxLength; - int? precision; - int? scale; + string fullTypeName; + string typeName; + bool isNullable; + int? maxLength; + int? precision; + int? scale; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(sql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(sql, con)) + cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find scalar function {tableFunctionName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - - typeName = reader.GetString("TypeName"); - isNullable = reader.GetBoolean("is_nullable"); - maxLength = reader.GetInt32OrNull("max_length"); - precision = reader.GetInt32OrNull("precision"); - scale = reader.GetInt32OrNull("scale"); - AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find scalar function {tableFunctionName}"); + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); + + typeName = reader.GetString("TypeName"); + isNullable = reader.GetBoolean("is_nullable"); + maxLength = reader.GetInt32OrNull("max_length"); + precision = reader.GetInt32OrNull("precision"); + scale = reader.GetInt32OrNull("scale"); + AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); } } - var objectName = new SqlServerObjectName(actualSchema, actualName); + } + var objectName = new SqlServerObjectName(actualSchema, actualName); - var parameters = GetParameters(objectName.ToString(), objectId); + var parameters = GetParameters(objectName.ToString(), objectId); - return new ScalarFunctionMetadata(objectName, parameters, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName); - } + return new ScalarFunctionMetadata(objectName, parameters, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName); + } - internal StoredProcedureMetadata GetStoredProcedureInternal(SqlServerObjectName procedureName) - { - const string StoredProcedureSql = - @"SELECT + internal StoredProcedureMetadata GetStoredProcedureInternal(SqlServerObjectName procedureName) + { + const string StoredProcedureSql = + @"SELECT s.name AS SchemaName, sp.name AS Name, sp.object_id AS ObjectId @@ -364,38 +364,38 @@ FROM SYS.procedures sp INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id WHERE s.name = ? AND sp.Name = ?"; - string actualSchema; - string actualName; - int objectId; + string actualSchema; + string actualName; + int objectId; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(StoredProcedureSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(StoredProcedureSql, con)) + cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", procedureName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", procedureName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find stored procedure {procedureName}"); + if (!reader.Read()) + throw new MissingObjectException($"Could not find stored procedure {procedureName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - } + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); } } - var objectName = new SqlServerObjectName(actualSchema, actualName); - var parameters = GetParameters(objectName.ToString(), objectId); - - return new StoredProcedureMetadata(objectName, parameters); } + var objectName = new SqlServerObjectName(actualSchema, actualName); + var parameters = GetParameters(objectName.ToString(), objectId); - internal TableFunctionMetadata GetTableFunctionInternal(SqlServerObjectName tableFunctionName) - { - const string TvfSql = - @"SELECT + return new StoredProcedureMetadata(objectName, parameters); + } + + internal TableFunctionMetadata GetTableFunctionInternal(SqlServerObjectName tableFunctionName) + { + const string TvfSql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId @@ -403,50 +403,50 @@ FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.type in ('TF', 'IF', 'FT') AND s.name = ? AND o.Name = ?"; - /* - * TF = SQL table-valued-function - * IF = SQL inline table-valued function - * FT = Assembly (CLR) table-valued function - */ + /* + * TF = SQL table-valued-function + * IF = SQL inline table-valued function + * FT = Assembly (CLR) table-valued function + */ - string actualSchema; - string actualName; - int objectId; + string actualSchema; + string actualName; + int objectId; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(TvfSql, con)) + cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find table valued function {tableFunctionName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find table valued function {tableFunctionName}"); + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); } } - var objectName = new SqlServerObjectName(actualSchema, actualName); + } + var objectName = new SqlServerObjectName(actualSchema, actualName); - var columns = GetColumns(tableFunctionName.ToString(), objectId); - var parameters = GetParameters(objectName.ToString(), objectId); + var columns = GetColumns(tableFunctionName.ToString(), objectId); + var parameters = GetParameters(objectName.ToString(), objectId); - return new TableFunctionMetadata(objectName, parameters, columns); - } + return new TableFunctionMetadata(objectName, parameters, columns); + } - internal SqlServerTableOrViewMetadata GetTableOrViewInternal(SqlServerObjectName tableName) - { - const string TableSql = - @"SELECT + internal SqlServerTableOrViewMetadata GetTableOrViewInternal(SqlServerObjectName tableName) + { + const string TableSql = + @"SELECT s.name AS SchemaName, t.name AS Name, t.object_id AS ObjectId, CONVERT(BIT, 1) AS IsTable, - (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers + (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers FROM SYS.tables t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE s.name = ? AND t.Name = ? @@ -458,49 +458,49 @@ UNION ALL t.name AS Name, t.object_id AS ObjectId, CONVERT(BIT, 0) AS IsTable, - (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers + (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers FROM SYS.views t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE s.name = ? AND t.Name = ?"; - string actualSchema; - string actualName; - int objectId; - bool isTable; - bool hasTriggers; + string actualSchema; + string actualName; + int objectId; + bool isTable; + bool hasTriggers; - using (var con = new OleDbConnection(m_ConnectionBuilder!.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder!.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(TableSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(TableSql, con)) + cmd.Parameters.AddWithValue("@Schema1", tableName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name1", tableName.Name); + cmd.Parameters.AddWithValue("@Schema2", tableName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name2", tableName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema1", tableName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name1", tableName.Name); - cmd.Parameters.AddWithValue("@Schema2", tableName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name2", tableName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find table or view {tableName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - isTable = reader.GetBoolean("IsTable"); - hasTriggers = reader.GetInt32("Triggers") > 0; - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find table or view {tableName}"); + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); + isTable = reader.GetBoolean("IsTable"); + hasTriggers = reader.GetInt32("Triggers") > 0; } } + } - var columns = GetColumns(tableName.ToString(), objectId); + var columns = GetColumns(tableName.ToString(), objectId); - return new SqlServerTableOrViewMetadata(this, new SqlServerObjectName(actualSchema, actualName), isTable, columns, hasTriggers); - } + return new SqlServerTableOrViewMetadata(this, new SqlServerObjectName(actualSchema, actualName), isTable, columns, hasTriggers); + } - internal UserDefinedTableTypeMetadata - GetUserDefinedTableTypeInternal(SqlServerObjectName typeName) - { - const string sql = - @"SELECT s.name AS SchemaName, + internal UserDefinedTableTypeMetadata + GetUserDefinedTableTypeInternal(SqlServerObjectName typeName) + { + const string sql = + @"SELECT s.name AS SchemaName, t.name AS Name, tt.type_table_object_id AS ObjectId FROM sys.types t @@ -509,90 +509,90 @@ FROM sys.types t LEFT JOIN sys.types t2 ON t.system_type_id = t2.user_type_id WHERE s.name = ? AND t.name = ? AND t.is_table_type = 1;"; - string actualSchema; - string actualName; + string actualSchema; + string actualName; - int objectId; + int objectId; - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(sql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(sql, con)) + cmd.Parameters.AddWithValue("@Schema", typeName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", typeName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", typeName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", typeName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find user defined type {typeName}"); + if (!reader.Read()) + throw new MissingObjectException($"Could not find user defined type {typeName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - } + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); } } + } - var columns = GetColumns(typeName.ToString(), objectId); + var columns = GetColumns(typeName.ToString(), objectId); - return new UserDefinedTableTypeMetadata(new SqlServerObjectName(actualSchema, actualName), columns); - } + return new UserDefinedTableTypeMetadata(new SqlServerObjectName(actualSchema, actualName), columns); + } - /// - /// Determines the database column type from the column type name. - /// - /// Name of the database column type. - /// NOT USED - /// - /// This does not honor registered types. This is only used for the database's hard-coded list of native types. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - protected override OleDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) + /// + /// Determines the database column type from the column type name. + /// + /// Name of the database column type. + /// NOT USED + /// + /// This does not honor registered types. This is only used for the database's hard-coded list of native types. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + protected override OleDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) + { + switch (typeName) { - switch (typeName) - { - case "bigint": return OleDbType.BigInt; - case "binary": return OleDbType.Binary; - case "bit": return OleDbType.Boolean; - case "char": return OleDbType.Char; - case "date": return OleDbType.DBDate; - case "datetime": return OleDbType.DBTimeStamp; - case "datetime2": return OleDbType.DBTimeStamp; - //case "datetimeoffset": return OleDbType; - case "decimal": return OleDbType.Decimal; - case "float": return OleDbType.Single; - //case "geography": m_SqlDbType = OleDbType.; - //case "geometry": m_SqlDbType = OleDbType; - //case "hierarchyid": m_SqlDbType = OleDbType.; - //case "image": return OleDbType.Image; - case "int": return OleDbType.Integer; - case "money": return OleDbType.Currency; - case "nchar": return OleDbType.WChar; - case "ntext": return OleDbType.LongVarWChar; - case "numeric": return OleDbType.Numeric; - case "nvarchar": return OleDbType.VarWChar; - case "real": return OleDbType.Single; - case "smalldatetime": return OleDbType.DBTimeStamp; - case "smallint": return OleDbType.SmallInt; - case "smallmoney": return OleDbType.Currency; - //case "sql_variant": m_SqlDbType = OleDbType; - //case "sysname": m_SqlDbType = OleDbType; - case "text": return OleDbType.LongVarWChar; - case "time": return OleDbType.DBTime; - case "timestamp": return OleDbType.DBTimeStamp; - case "tinyint": return OleDbType.TinyInt; - case "uniqueidentifier": return OleDbType.Guid; - case "varbinary": return OleDbType.VarBinary; - case "varchar": return OleDbType.VarChar; - //case "xml": return OleDbType; - } - - return null; + case "bigint": return OleDbType.BigInt; + case "binary": return OleDbType.Binary; + case "bit": return OleDbType.Boolean; + case "char": return OleDbType.Char; + case "date": return OleDbType.DBDate; + case "datetime": return OleDbType.DBTimeStamp; + case "datetime2": return OleDbType.DBTimeStamp; + //case "datetimeoffset": return OleDbType; + case "decimal": return OleDbType.Decimal; + case "float": return OleDbType.Single; + //case "geography": m_SqlDbType = OleDbType.; + //case "geometry": m_SqlDbType = OleDbType; + //case "hierarchyid": m_SqlDbType = OleDbType.; + //case "image": return OleDbType.Image; + case "int": return OleDbType.Integer; + case "money": return OleDbType.Currency; + case "nchar": return OleDbType.WChar; + case "ntext": return OleDbType.LongVarWChar; + case "numeric": return OleDbType.Numeric; + case "nvarchar": return OleDbType.VarWChar; + case "real": return OleDbType.Single; + case "smalldatetime": return OleDbType.DBTimeStamp; + case "smallint": return OleDbType.SmallInt; + case "smallmoney": return OleDbType.Currency; + //case "sql_variant": m_SqlDbType = OleDbType; + //case "sysname": m_SqlDbType = OleDbType; + case "text": return OleDbType.LongVarWChar; + case "time": return OleDbType.DBTime; + case "timestamp": return OleDbType.DBTimeStamp; + case "tinyint": return OleDbType.TinyInt; + case "uniqueidentifier": return OleDbType.Guid; + case "varbinary": return OleDbType.VarBinary; + case "varchar": return OleDbType.VarChar; + //case "xml": return OleDbType; } - ColumnMetadataCollection GetColumns(string ownerName, int objectId) - { - const string ColumnSql = - @"WITH PKS + return null; + } + + ColumnMetadataCollection GetColumns(string ownerName, int objectId) + { + const string ColumnSql = + @"WITH PKS AS ( SELECT c.name , 1 AS is_primary_key FROM sys.indexes i @@ -611,106 +611,105 @@ FROM sys.indexes i Convert(bit, ISNULL(PKS.is_primary_key, 0)) AS is_primary_key, COALESCE(t.name, t2.name) AS TypeName, c.is_nullable, - CONVERT(INT, COALESCE(c.max_length, t.max_length, t2.max_length)) AS max_length, - CONVERT(INT, COALESCE(c.precision, t.precision, t2.precision)) AS precision, - CONVERT(INT, COALESCE(c.scale, t.scale, t2.scale)) AS scale + CONVERT(INT, COALESCE(c.max_length, t.max_length, t2.max_length)) AS max_length, + CONVERT(INT, COALESCE(c.precision, t.precision, t2.precision)) AS precision, + CONVERT(INT, COALESCE(c.scale, t.scale, t2.scale)) AS scale FROM sys.columns c LEFT JOIN PKS ON c.name = PKS.name LEFT JOIN sys.types t on c.system_type_id = t.user_type_id LEFT JOIN sys.types t2 ON c.user_type_id = t2.user_type_id - WHERE object_id = ?;"; + WHERE object_id = ?;"; - var columns = new List>(); - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + var columns = new List>(); + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new OleDbCommand(ColumnSql, con)) { - con.Open(); - using (var cmd = new OleDbCommand(ColumnSql, con)) + cmd.Parameters.AddWithValue("@ObjectId1", objectId); + cmd.Parameters.AddWithValue("@ObjectId2", objectId); + cmd.Parameters.AddWithValue("@ObjectId3", objectId); + cmd.Parameters.AddWithValue("@ObjectId4", objectId); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@ObjectId1", objectId); - cmd.Parameters.AddWithValue("@ObjectId2", objectId); - cmd.Parameters.AddWithValue("@ObjectId3", objectId); - cmd.Parameters.AddWithValue("@ObjectId4", objectId); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var name = reader.GetString("ColumnName"); - var computed = reader.GetBoolean("is_computed"); - var primary = reader.GetBoolean("is_primary_key"); - var isIdentity = reader.GetBoolean("is_identity"); - var typeName = reader.GetString("TypeName"); - var isNullable = reader.GetBoolean("is_nullable"); - int? maxLength = reader.GetInt32OrNull("max_length"); - int? precision = reader.GetInt32OrNull("precision"); - int? scale = reader.GetInt32OrNull("scale"); - string fullTypeName; - AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); + var name = reader.GetString("ColumnName"); + var computed = reader.GetBoolean("is_computed"); + var primary = reader.GetBoolean("is_primary_key"); + var isIdentity = reader.GetBoolean("is_identity"); + var typeName = reader.GetString("TypeName"); + var isNullable = reader.GetBoolean("is_nullable"); + int? maxLength = reader.GetInt32OrNull("max_length"); + int? precision = reader.GetInt32OrNull("precision"); + int? scale = reader.GetInt32OrNull("scale"); + string fullTypeName; + AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); - columns.Add(new ColumnMetadata(name, computed, primary, isIdentity, typeName, SqlTypeNameToDbType(typeName), "[" + name + "]", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, maxLength))); - } + columns.Add(new ColumnMetadata(name, computed, primary, isIdentity, typeName, SqlTypeNameToDbType(typeName), "[" + name + "]", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, maxLength))); } } } - return new ColumnMetadataCollection(ownerName, columns); } + return new ColumnMetadataCollection(ownerName, columns); + } - ParameterMetadataCollection GetParameters(string procedureName, int objectId) + ParameterMetadataCollection GetParameters(string procedureName, int objectId) + { + try { - try - { - const string ParameterSql = - @"SELECT p.name AS ParameterName , - COALESCE(t.name, t2.name) AS TypeName, + const string ParameterSql = + @"SELECT p.name AS ParameterName , + COALESCE(t.name, t2.name) AS TypeName, COALESCE(t.is_nullable, t2.is_nullable) as is_nullable, - CONVERT(INT, t.max_length) AS max_length, - CONVERT(INT, t.precision) AS precision, - CONVERT(INT, t.scale) AS scale, - p.is_output - FROM sys.parameters p - LEFT JOIN sys.types t ON p.system_type_id = t.user_type_id - LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id - WHERE p.object_id = ? AND p.parameter_id <> 0 - ORDER BY p.parameter_id;"; + CONVERT(INT, t.max_length) AS max_length, + CONVERT(INT, t.precision) AS precision, + CONVERT(INT, t.scale) AS scale, + p.is_output + FROM sys.parameters p + LEFT JOIN sys.types t ON p.system_type_id = t.user_type_id + LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id + WHERE p.object_id = ? AND p.parameter_id <> 0 + ORDER BY p.parameter_id;"; - //we exclude parameter_id 0 because it is the return type of scalar functions. + //we exclude parameter_id 0 because it is the return type of scalar functions. - var parameters = new List>(); + var parameters = new List>(); - using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); + using (var con = new OleDbConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); - using (var cmd = new OleDbCommand(ParameterSql, con)) + using (var cmd = new OleDbCommand(ParameterSql, con)) + { + cmd.Parameters.AddWithValue("@ObjectId", objectId); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@ObjectId", objectId); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var name = reader.GetString("ParameterName"); - var typeName = reader.GetString("TypeName"); - bool isNullable = true; - int? maxLength = reader.GetInt32OrNull("max_length"); - int? precision = reader.GetInt32OrNull("precision"); - int? scale = reader.GetInt32OrNull("scale"); - var isOutput = reader.GetBoolean("is_output"); - - string fullTypeName; - AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); - - var direction = isOutput ? ParameterDirection.Output : ParameterDirection.Input; - - parameters.Add(new ParameterMetadata(name, name, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName, direction)); - } + var name = reader.GetString("ParameterName"); + var typeName = reader.GetString("TypeName"); + bool isNullable = true; + int? maxLength = reader.GetInt32OrNull("max_length"); + int? precision = reader.GetInt32OrNull("precision"); + int? scale = reader.GetInt32OrNull("scale"); + var isOutput = reader.GetBoolean("is_output"); + + string fullTypeName; + AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); + + var direction = isOutput ? ParameterDirection.Output : ParameterDirection.Input; + + parameters.Add(new ParameterMetadata(name, name, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName, direction)); } } } - return new ParameterMetadataCollection(procedureName, parameters); - } - catch (Exception ex) - { - throw new MetadataException($"Error getting parameters for {procedureName}", ex); } + return new ParameterMetadataCollection(procedureName, parameters); + } + catch (Exception ex) + { + throw new MetadataException($"Error getting parameters for {procedureName}", ex); } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerOpenDataSource.cs index 076b225b2..90c54f671 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerOpenDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerOpenDataSource.cs @@ -3,204 +3,202 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerOpenDataSource. +/// +[UseTrait(typeof(Traits.OpenDataSourceTrait))] +public partial class OleDbSqlServerOpenDataSource : OleDbSqlServerDataSourceBase { + internal OleDbSqlServerOpenDataSource(OleDbSqlServerDataSource dataSource, OleDbConnection connection, OleDbTransaction? transaction) : base(new SqlServerDataSourceSettings(dataSource)) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + + m_BaseDataSource = dataSource; + m_Connection = connection; + m_Transaction = transaction; + } + /// - /// Class SqlServerOpenDataSource. + /// Executes the specified operation. /// - [UseTrait(typeof(Traits.OpenDataSourceTrait))] - public partial class OleDbSqlServerOpenDataSource : OleDbSqlServerDataSourceBase + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) { - internal OleDbSqlServerOpenDataSource(OleDbSqlServerDataSource dataSource, OleDbConnection connection, OleDbTransaction? transaction) : base(new SqlServerDataSourceSettings(dataSource)) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - - m_BaseDataSource = dataSource; - m_Connection = connection; - m_Transaction = transaction; - } + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try - { - using (var cmd = new OleDbCommand()) - { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) + using (var cmd = new OleDbCommand()) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + try + { + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var cmd = new OleDbCommand()) { - var rows = implementation(m_Connection, m_Transaction); + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } } - - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var cmd = new OleDbCommand()) - { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - private partial OleDbSqlServerOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) - { - if (userValue != null) - UserValue = userValue; - if (additionalRules != null) - AuditRules = new AuditRuleCollection(AuditRules, additionalRules); + private partial OleDbSqlServerOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) + { + if (userValue != null) + UserValue = userValue; + if (additionalRules != null) + AuditRules = new AuditRuleCollection(AuditRules, additionalRules); - return this; - } + return this; } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerTransactionalDataSource..cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerTransactionalDataSource..cs index 69f7f486f..8622cfccd 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerTransactionalDataSource..cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/OleDbSqlServerTransactionalDataSource..cs @@ -2,245 +2,239 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerTransactionalDataSource. +/// +[UseTrait(typeof(Traits.TransactionalDataSourceTrait))] +public partial class OleDbSqlServerTransactionalDataSource : OleDbSqlServerDataSourceBase { /// - /// Class SqlServerTransactionalDataSource. + /// Initializes a new instance of the class. /// - [UseTrait(typeof(Traits.TransactionalDataSourceTrait))] - public partial class OleDbSqlServerTransactionalDataSource : OleDbSqlServerDataSourceBase + /// The parent connection. + /// Name of the transaction. + /// The isolation level. If not supplied, will use the database default. + /// If true, logging events are forwarded to the parent connection. + public OleDbSqlServerTransactionalDataSource(OleDbSqlServerDataSource dataSource, string? transactionName, IsolationLevel? isolationLevel, bool forwardEvents) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) { - /// - /// Initializes a new instance of the class. - /// - /// The parent connection. - /// Name of the transaction. - /// The isolation level. If not supplied, will use the database default. - /// If true, logging events are forwarded to the parent connection. - public OleDbSqlServerTransactionalDataSource(OleDbSqlServerDataSource dataSource, string? transactionName, IsolationLevel? isolationLevel, bool forwardEvents) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) - { - Name = dataSource.Name; + Name = dataSource.Name; - m_BaseDataSource = dataSource; - m_Connection = dataSource.CreateConnection(); - TransactionName = transactionName; + m_BaseDataSource = dataSource; + m_Connection = dataSource.CreateConnection(); + TransactionName = transactionName; - if (isolationLevel == null) - m_Transaction = m_Connection.BeginTransaction(); - else - m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value); + if (isolationLevel == null) + m_Transaction = m_Connection.BeginTransaction(); + else + m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value); - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } - /// - /// Initializes a new instance of the class. - /// - /// The parent connection. - /// Name of the transaction. - /// If true, logging events are forwarded to the parent connection. - /// The connection. - /// The transaction. - internal OleDbSqlServerTransactionalDataSource(OleDbSqlServerDataSource dataSource, string? transactionName, bool forwardEvents, OleDbConnection connection, OleDbTransaction transaction) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) - { - Name = dataSource.Name; + /// + /// Initializes a new instance of the class. + /// + /// The parent connection. + /// Name of the transaction. + /// If true, logging events are forwarded to the parent connection. + /// The connection. + /// The transaction. + internal OleDbSqlServerTransactionalDataSource(OleDbSqlServerDataSource dataSource, string? transactionName, bool forwardEvents, OleDbConnection connection, OleDbTransaction transaction) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) + { + Name = dataSource.Name; - m_BaseDataSource = dataSource; - m_Connection = connection; - TransactionName = transactionName; - m_Transaction = transaction; + m_BaseDataSource = dataSource; + m_Connection = connection; + TransactionName = transactionName; + m_Transaction = transaction; - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } + /// + /// Gets the name of the transaction. + /// + /// The name of the transaction. + public string? TransactionName { get; } + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - /// - /// Gets the name of the transaction. - /// - /// The name of the transaction. - public string? TransactionName { get; } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + using (var cmd = new OleDbCommand()) { - using (var cmd = new OleDbCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - try + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + using (var cmd = new OleDbCommand()) { - var rows = implementation(m_Connection, m_Transaction); + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + if (DefaultCommandTimeout.HasValue) + cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; + cmd.CommandText = executionToken.CommandText; + cmd.CommandType = executionToken.CommandType; + foreach (var param in executionToken.Parameters) + cmd.Parameters.Add(param); + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var cmd = new OleDbCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } - - - } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/Utilities.cs index 8b80fa95b..ab413fc70 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/SqlServer/Utilities.cs @@ -1,54 +1,90 @@ -using System; -using System.Collections.Generic; -using System.Data.OleDb; -using System.Linq; +using System.Data.OleDb; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +internal static class Utilities { - internal static class Utilities - { - /// - /// Gets the parameters from a SQL Builder. - /// - /// The SQL builder. - /// - public static List GetParameters(this SqlBuilder sqlBuilder) - { - return sqlBuilder.GetParameters((SqlBuilderEntry entry) => - { - var result = new OleDbParameter(); - result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; - - if (entry.Details.DbType.HasValue) - { - result.OleDbType = entry.Details.DbType.Value; - - if (entry.Details.TypeName == "datetime2" && entry.Details.Scale.HasValue) - result.Scale = (byte)entry.Details.Scale.Value; - } - return result; - }); - } - - /// - /// Triggers need special handling for OUTPUT clauses. - /// - public static void UseTableVariable(this SqlBuilder sqlBuilder, SqlServerTableOrViewMetadata Table, out string? header, out string? intoClause, out string? footer) where TDbType : struct - { - if (sqlBuilder.HasReadFields && Table.HasTriggers) - { - header = "DECLARE @ResultTable TABLE( " + string.Join(", ", sqlBuilder.GetSelectColumnDetails().Select(c => c.QuotedSqlName + " " + c.FullTypeName + " NULL")) + ");" + Environment.NewLine; - intoClause = " INTO @ResultTable "; - footer = Environment.NewLine + "SELECT * FROM @ResultTable"; - } - else - { - header = null; - intoClause = null; - footer = null; - } - } - } -} + /// + /// Gets the parameters from a SQL Builder. + /// + /// The SQL builder. + /// + public static List GetParameters(this SqlBuilder sqlBuilder) + { + return sqlBuilder.GetParameters((SqlBuilderEntry entry) => + { + var result = new OleDbParameter(); + result.ParameterName = entry.Details.SqlVariableName; + +#if NET6_0_OR_GREATER + result.Value = entry.ParameterValue switch + { + DateOnly dateOnly => dateOnly.ToDateTime(default), + TimeOnly timeOnly => timeOnly.ToTimeSpan(), + _ => entry.ParameterValue + }; +#else + result.Value = entry.ParameterValue; +#endif + + if (entry.Details.DbType.HasValue) + { + result.OleDbType = entry.Details.DbType.Value; + + if (entry.Details.TypeName == "datetime2" && entry.Details.Scale.HasValue) + result.Scale = (byte)entry.Details.Scale.Value; + else if (entry.Details.TypeName == "time" && entry.Details.Scale > 0) + { + //If we need fractions of a second, force a type change. + //OleDbType.DBTime does not support milliseconds. + //OleDbType.DBTimeStamp only accepts DateTime. + + result.OleDbType = OleDbType.DBTimeStamp; + result.Scale = (byte)entry.Details.Scale.Value; + + if (result.Value is TimeSpan tv) + { + result.Value = default(DateTime) + tv; + } + } + } + return result; + }); + } + + public static bool RequiresSorting(this SqlServerLimitOption limitOption) + { + return limitOption switch + { + SqlServerLimitOption.None => false, + SqlServerLimitOption.Rows => true, + SqlServerLimitOption.Percentage => true, + SqlServerLimitOption.RowsWithTies => true, + SqlServerLimitOption.PercentageWithTies => true, + SqlServerLimitOption.TableSampleSystemRows => false, + SqlServerLimitOption.TableSampleSystemPercentage => false, + _ => throw new ArgumentOutOfRangeException(nameof(limitOption), limitOption, "Unknown limit option") + }; + } + + /// + /// Triggers need special handling for OUTPUT clauses. + /// + public static void UseTableVariable(this SqlBuilder sqlBuilder, SqlServerTableOrViewMetadata table, out string? header, out string? intoClause, out string? footer) + where TDbType : struct + { + if (sqlBuilder.HasReadFields && table.HasTriggers) + { + header = "DECLARE @ResultTable TABLE( " + string.Join(", ", sqlBuilder.GetSelectColumnDetails().Select(c => c.QuotedSqlName + " " + c.FullTypeName + " NULL")) + ");" + Environment.NewLine; + intoClause = " INTO @ResultTable "; + footer = Environment.NewLine + "SELECT * FROM @ResultTable"; + } + else + { + header = null; + intoClause = null; + footer = null; + } + } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Tortuga.Chain.SqlServer.OleDb.csproj b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Tortuga.Chain.SqlServer.OleDb.csproj index 2c4a35c76..682fa6f17 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Tortuga.Chain.SqlServer.OleDb.csproj +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer.OleDb/Tortuga.Chain.SqlServer.OleDb.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -67,7 +67,7 @@ - + @@ -79,7 +79,7 @@ - true + Generated @@ -87,7 +87,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs deleted file mode 100644 index 4dd85dc98..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Logs.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* -Container class: Tortuga.Chain.SqlServerDataSource - Adding trait: Traits.RootDataSourceTrait -Container class: Tortuga.Chain.SqlServer.SqlServerDataSourceBase - Adding trait: Traits.SupportsDeleteAllTrait - Adding trait: Traits.SupportsTruncateTrait - Adding trait: Traits.SupportsSqlQueriesTrait - Adding trait: Traits.SupportsInsertBatchTrait> - Adding trait: Traits.SupportsDeleteByKeyListTrait - Adding trait: Traits.SupportsDeleteTrait - Adding trait: Traits.SupportsUpdateTrait - Adding trait: Traits.SupportsUpdateByKeyListTrait - Adding trait: Traits.SupportsInsertTrait - Adding trait: Traits.SupportsUpdateSet - Adding trait: Traits.SupportsDeleteSet - Adding trait: Traits.SupportsFromTrait - Adding trait: Traits.SupportsGetByKeyListTrait - Adding trait: Traits.SupportsUpsertTrait - Adding trait: Traits.SupportsInsertBulkTrait - Adding trait: Traits.SupportsScalarFunctionTrait - Adding trait: Traits.SupportsProcedureTrait - Adding trait: Traits.SupportsTableFunctionTrait -Container class: Tortuga.Chain.SqlServer.SqlServerOpenDataSource - Adding trait: Traits.OpenDataSourceTrait -Container class: Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource - Adding trait: Traits.TransactionalDataSourceTrait -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Traits.IHasExtensionCache.get_ExtensionCache -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedConnection -Unable to process interface member of type Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel.MethodSymbol named Tortuga.Chain.DataSources.IOpenDataSource.get_AssociatedTransaction -*/ \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerDataSourceBase.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerDataSourceBase.cs deleted file mode 100644 index 20e660d63..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerDataSourceBase.cs +++ /dev/null @@ -1,1408 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class SqlServerDataSourceBase: Tortuga.Chain.DataSources.ISupportsDeleteAll, Tortuga.Chain.DataSources.ISupportsTruncate, Tortuga.Chain.DataSources.ISupportsSqlQueries, Tortuga.Chain.DataSources.ISupportsInsertBatch, Tortuga.Chain.DataSources.ISupportsDeleteByKeyList, Tortuga.Chain.DataSources.ISupportsDeleteByKey, Tortuga.Chain.DataSources.ISupportsDelete, Tortuga.Chain.DataSources.ISupportsUpdate, Tortuga.Chain.DataSources.ISupportsUpdateByKey, Tortuga.Chain.DataSources.ISupportsUpdateByKeyList, Tortuga.Chain.DataSources.ISupportsInsert, Tortuga.Chain.DataSources.ISupportsUpdateSet, Tortuga.Chain.DataSources.ISupportsDeleteSet, Tortuga.Chain.DataSources.ISupportsFrom, Tortuga.Chain.DataSources.ISupportsGetByKeyList, Tortuga.Chain.DataSources.ISupportsGetByKey, Tortuga.Chain.DataSources.ISupportsUpsert, Tortuga.Chain.DataSources.ISupportsInsertBulk, Tortuga.Chain.DataSources.ISupportsScalarFunction, Tortuga.Chain.DataSources.ISupportsProcedure, Tortuga.Chain.DataSources.ISupportsTableFunction, Traits.ICommandHelper, Traits.IInsertBatchHelper, Traits.IUpdateDeleteByKeyHelper, Traits.IUpdateDeleteHelper, Traits.IInsertHelper, Traits.IUpdateDeleteSetHelper, Traits.IFromHelper, Traits.IGetByKeyHelper, Traits.IUpsertHelper, Traits.IInsertBulkHelper, Traits.ICommandHelper - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.SupportsDeleteAllTrait ___Trait0 = new(); - private Traits.SupportsDeleteAllTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - private Traits.SupportsTruncateTrait ___Trait1 = new(); - private Traits.SupportsTruncateTrait __Trait1 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait1; - } - } - private Traits.SupportsSqlQueriesTrait ___Trait2 = new(); - private Traits.SupportsSqlQueriesTrait __Trait2 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait2; - } - } - private Traits.SupportsInsertBatchTrait> ___Trait3 = new(); - private Traits.SupportsInsertBatchTrait> __Trait3 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait3; - } - } - private Traits.SupportsDeleteByKeyListTrait ___Trait4 = new(); - private Traits.SupportsDeleteByKeyListTrait __Trait4 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait4; - } - } - private Traits.SupportsDeleteTrait ___Trait5 = new(); - private Traits.SupportsDeleteTrait __Trait5 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait5; - } - } - private Traits.SupportsUpdateTrait ___Trait6 = new(); - private Traits.SupportsUpdateTrait __Trait6 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait6; - } - } - private Traits.SupportsUpdateByKeyListTrait ___Trait7 = new(); - private Traits.SupportsUpdateByKeyListTrait __Trait7 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait7; - } - } - private Traits.SupportsInsertTrait ___Trait8 = new(); - private Traits.SupportsInsertTrait __Trait8 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait8; - } - } - private Traits.SupportsUpdateSet ___Trait9 = new(); - private Traits.SupportsUpdateSet __Trait9 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait9; - } - } - private Traits.SupportsDeleteSet ___Trait10 = new(); - private Traits.SupportsDeleteSet __Trait10 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait10; - } - } - private Traits.SupportsFromTrait ___Trait11 = new(); - private Traits.SupportsFromTrait __Trait11 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait11; - } - } - private Traits.SupportsGetByKeyListTrait ___Trait12 = new(); - private Traits.SupportsGetByKeyListTrait __Trait12 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait12; - } - } - private Traits.SupportsUpsertTrait ___Trait13 = new(); - private Traits.SupportsUpsertTrait __Trait13 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait13; - } - } - private Traits.SupportsInsertBulkTrait ___Trait14 = new(); - private Traits.SupportsInsertBulkTrait __Trait14 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait14; - } - } - private Traits.SupportsScalarFunctionTrait ___Trait15 = new(); - private Traits.SupportsScalarFunctionTrait __Trait15 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait15; - } - } - private Traits.SupportsProcedureTrait ___Trait16 = new(); - private Traits.SupportsProcedureTrait __Trait16 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait16; - } - } - private Traits.SupportsTableFunctionTrait ___Trait17 = new(); - private Traits.SupportsTableFunctionTrait __Trait17 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait17; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDelete - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(System.String tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait5).Delete(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDelete.Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDelete)__Trait5).Delete(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteAll - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsDeleteAll.DeleteAll() - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteAll)__Trait0).DeleteAll(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, TKey key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKey.DeleteByKey(System.String tableName, System.String key, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKey)__Trait4).DeleteByKey(tableName, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteByKeyList.DeleteByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteByKeyList)__Trait4).DeleteByKeyList(tableName, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsDeleteSet - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.String whereClause, System.Object? argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsDeleteSet.DeleteSet(System.String tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsDeleteSet)__Trait10).DeleteSet(tableName, filterValue, filterOptions); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsFrom - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(tableOrViewName, filterValue, filterOptions); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From() - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.String whereClause, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(whereClause, argumentValue); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsFrom.From(System.Object filterValue) - { - return ((Tortuga.Chain.DataSources.ISupportsFrom)__Trait11).From(filterValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String tableName, System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(tableName, key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(TKey key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.String key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int32 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Int64 key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKey.GetByKey(System.Guid key) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKey)__Trait12).GetByKey(key); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsGetByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(keys); - } - - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsGetByKeyList.GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return ((Tortuga.Chain.DataSources.ISupportsGetByKeyList)__Trait12).GetByKeyList(tableName, keyColumn, keys); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(System.String tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsert.Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsert)__Trait8).Insert(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBatch - Tortuga.Chain.CommandBuilders.IDbCommandBuilder Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertBatch(objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.String tableName, System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(tableName, objects, options); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBatch.InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBatch)__Trait3).InsertMultipleBatch(objects, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsInsertBulk - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.String tableName, System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(tableName, objects); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.DataTable dataTable) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataTable); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Data.IDataReader dataReader) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(dataReader); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsInsertBulk.InsertBulk(System.Collections.Generic.IEnumerable objects) - { - return ((Tortuga.Chain.DataSources.ISupportsInsertBulk)__Trait14).InsertBulk(objects); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsProcedure - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName); - } - - Tortuga.Chain.CommandBuilders.IProcedureDbCommandBuilder Tortuga.Chain.DataSources.ISupportsProcedure.Procedure(System.String procedureName, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsProcedure)__Trait16).Procedure(procedureName, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsScalarFunction - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName); - } - - Tortuga.Chain.CommandBuilders.IScalarDbCommandBuilder Tortuga.Chain.DataSources.ISupportsScalarFunction.ScalarFunction(System.String scalarFunctionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsScalarFunction)__Trait15).ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsSqlQueries - Tortuga.Chain.CommandBuilders.IMultipleTableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsSqlQueries.Sql(System.String sqlStatement, System.Object argumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsSqlQueries)__Trait2).Sql(sqlStatement, argumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTableFunction - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait17).TableFunction(functionName); - } - - Tortuga.Chain.CommandBuilders.ITableDbCommandBuilder Tortuga.Chain.DataSources.ISupportsTableFunction.TableFunction(System.String functionName, System.Object functionArgumentValue) - { - return ((Tortuga.Chain.DataSources.ISupportsTableFunction)__Trait17).TableFunction(functionName, functionArgumentValue); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsTruncate - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate(System.String tableName) - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(tableName); - } - - Tortuga.Chain.ILink Tortuga.Chain.DataSources.ISupportsTruncate.Truncate() - { - return ((Tortuga.Chain.DataSources.ISupportsTruncate)__Trait1).Truncate(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdate - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait6).Update(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdate.Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdate)__Trait6).Update(argumentValue, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKey - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - Tortuga.Chain.CommandBuilders.ISingleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKey.UpdateByKey(System.String tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKey)__Trait7).UpdateByKey(tableName, newValues, key, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateByKeyList - Tortuga.Chain.CommandBuilders.IMultipleRowDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateByKeyList.UpdateByKeyList(System.String tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateByKeyList)__Trait7).UpdateByKeyList(tableName, newValues, keys, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpdateSet - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpdateSet.UpdateSet(System.String tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpdateSet)__Trait9).UpdateSet(tableName, newValues, options); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ISupportsUpsert - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(System.String tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(tableName, argumentValue, options); - } - - Tortuga.Chain.CommandBuilders.IObjectDbCommandBuilder Tortuga.Chain.DataSources.ISupportsUpsert.Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options) - { - return ((Tortuga.Chain.DataSources.ISupportsUpsert)__Trait13).Upsert(argumentValue, options); - } - - // Exposing trait Traits.SupportsDeleteAllTrait - - /// Deletes all records in the specified table. - /// Name of the table to clear. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll(Tortuga.Chain.SqlServer.SqlServerObjectName tableName) - { - return __Trait0.DeleteAll(tableName); - } - - /// Deletes all records in the specified table. - /// This class used to determine which table to clear - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink DeleteAll()where TObject : class - { - return __Trait0.DeleteAll(); - } - - // Exposing trait Traits.SupportsDeleteByKeyListTrait - - /// - /// Delete a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<TCommand, TParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, T key, Tortuga.Chain.DeleteOptions options = 0)where T : struct - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Name of the table. - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String key, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKey(tableName, key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Guid key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int64 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.Int32 key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete a record by its primary key. - /// - /// Used to determine the table name - /// The key. - /// The options. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder DeleteByKey(System.String key, Tortuga.Chain.DeleteOptions options = 0)where TObject : class - { - return __Trait4.DeleteByKey(key, options); - } - - /// - /// Delete multiple rows by key. - /// - /// The type of the t key. - /// Name of the table. - /// The keys. - /// Delete options. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.DeleteOptions options = 0) - { - return __Trait4.DeleteByKeyList(tableName, keys, options); - } - - // Exposing trait Traits.SupportsDeleteSet - - /// - /// Delete multiple records using a filter object. - /// - /// Name of the table. - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait10.DeleteSet(tableName, filterValue, filterOptions); - } - - /// - /// Delete multiple records using a filter object. - /// - /// The filter value. - /// The options. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait10.DeleteSet(filterValue, filterOptions); - } - - /// - /// Delete multiple records using a where expression. - /// - /// Name of the table. - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String whereClause, System.Object? argumentValue = default) - { - return __Trait10.DeleteSet(tableName, whereClause, argumentValue); - } - - /// - /// Delete multiple records using a where expression. - /// - /// The where clause. - /// The argument value for the where clause. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder DeleteSet(System.String whereClause, System.Object? argumentValue = default)where TObject : class - { - return __Trait10.DeleteSet(whereClause, argumentValue); - } - - // Exposing trait Traits.SupportsDeleteTrait - - /// - /// Creates a command to perform a delete operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait5.Delete(tableName, argumentValue, options); - } - - /// - /// Delete an object model from the table indicated by the class's Table attribute. - /// - /// - /// The argument value. - /// The delete options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Delete(TArgument argumentValue, Tortuga.Chain.DeleteOptions options = 0)where TArgument : class - { - return __Trait5.Delete(argumentValue, options); - } - - // Exposing trait Traits.SupportsFromTrait - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName) - { - return __Trait11.From(tableOrViewName); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.String whereClause) - { - return __Trait11.From(tableOrViewName, whereClause); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.String whereClause, System.Object argumentValue) - { - return __Trait11.From(tableOrViewName, whereClause, argumentValue); - } - - /// - /// Creates an operation to directly query a table or view - /// - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(Tortuga.Chain.SqlServer.SqlServerObjectName tableOrViewName, System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0) - { - return __Trait11.From(tableOrViewName, filterValue, filterOptions); - } - - /// - /// This is used to directly query a table or view. - /// - /// - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From()where TObject : class - { - return __Trait11.From(); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause)where TObject : class - { - return __Trait11.From(whereClause); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The where clause. Do not prefix this clause with "WHERE". - /// Optional argument value. Every property in the argument value must have a matching parameter in the WHERE clause - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.String whereClause, System.Object argumentValue)where TObject : class - { - return __Trait11.From(whereClause, argumentValue); - } - - /// - /// This is used to directly query a table or view. - /// - /// The type of the object. - /// The filter value is used to generate a simple AND style WHERE clause. - /// The filter options. - /// TableDbCommandBuilder<TCommand, TParameter, TLimitOption, TObject>. - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder From(System.Object filterValue, Tortuga.Chain.FilterOptions filterOptions = 0)where TObject : class - { - return __Trait11.From(filterValue, filterOptions); - } - - // Exposing trait Traits.SupportsGetByKeyListTrait - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. Used to determine which table will be read. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Guid key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int64 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.Int32 key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(System.String key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// The type of the object. - /// The type of the key. - /// The key. - /// - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(TKey key)where TObject : class - { - return __Trait12.GetByKey(key); - } - - /// - /// Gets a record by its primary key. - /// - /// Name of the table. - /// The key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a record by its primary key. - /// - /// - /// Name of the table. - /// The key. - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder GetByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TKey key) - { - return __Trait12.GetByKey(tableName, key); - } - - /// - /// Gets a set of records by their primary key. - /// - /// - /// Name of the table. - /// The keys. - /// - /// This only works on tables that have a scalar primary key. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The type of the key. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// - /// Gets a set of records by a key list. - /// - /// The type of the returned object. - /// The keys. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.Collections.Generic.IEnumerable keys)where TObject : class - { - return __Trait12.GetByKeyList(keys); - } - - /// Gets a set of records by an unique key. - /// The type of the t key. - /// Name of the table. - /// Name of the key column. This should be a primary or unique key, but that's not enforced. - /// The keys. - /// IMultipleRowDbCommandBuilder. - [System.Obsolete(@"This will be replaced by GetByColumn")] - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder GetByKeyList(System.String tableName, System.String keyColumn, System.Collections.Generic.IEnumerable keys) - { - return __Trait12.GetByKeyList(tableName, keyColumn, keys); - } - - // Exposing trait Traits.SupportsInsertBatchTrait> - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// Name of the table. - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder InsertBatch(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder InsertBatch(System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertBatch(objects, options); - } - - /// - /// Performs a series of batch inserts. - /// - /// The type of the t object. - /// Name of the table. - /// The objects. - /// The options. - /// Tortuga.Chain.ILink<System.Int32>. - /// This operation is not atomic. It should be wrapped in a transaction. - public Tortuga.Chain.ILink InsertMultipleBatch(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(tableName, objects, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// The objects to insert. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public Tortuga.Chain.ILink InsertMultipleBatch(System.Collections.Generic.IReadOnlyList objects, Tortuga.Chain.InsertOptions options = 0)where TObject : class - { - return __Trait3.InsertMultipleBatch(objects, options); - } - - // Exposing trait Traits.SupportsInsertBulkTrait - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data table. - /// TInsertBulkCommand. - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Data.DataTable dataTable) - { - return __Trait14.InsertBulk(tableName, dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data reader. - /// TInsertBulkCommand. - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Data.IDataReader dataReader) - { - return __Trait14.InsertBulk(tableName, dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// - /// Name of the table. - /// The objects. - /// TInsertBulkCommand. - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(tableName, objects); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data table. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(System.Data.DataTable dataTable)where TObject : class - { - return __Trait14.InsertBulk(dataTable); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data reader. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(System.Data.IDataReader dataReader)where TObject : class - { - return __Trait14.InsertBulk(dataReader); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The objects. - /// - /// TInsertBulkCommand. - /// - public Tortuga.Chain.SqlServer.CommandBuilders.SqlServerInsertBulk InsertBulk(System.Collections.Generic.IEnumerable objects)where TObject : class - { - return __Trait14.InsertBulk(objects); - } - - // Exposing trait Traits.SupportsInsertTrait - - /// - /// Inserts an object into the specified table. - /// - /// - /// The argument value. - /// The options for how the insert occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(argumentValue, options); - } - - /// - /// Creates an operation used to perform an insert operation. - /// - /// Name of the table. - /// The argument value. - /// The options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Insert(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.InsertOptions options = 0)where TArgument : class - { - return __Trait8.Insert(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsProcedureTrait - - /// - /// Loads a procedure definition - /// - /// Name of the procedure. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName) - { - return __Trait16.Procedure(procedureName); - } - - /// - /// Loads a procedure definition and populates it using the parameter object. - /// - /// Name of the procedure. - /// The argument value. - /// - /// - /// The procedure's definition is loaded from the database and used to determine which properties on the parameter object to use. - /// - public Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder Procedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName, System.Object argumentValue) - { - return __Trait16.Procedure(procedureName, argumentValue); - } - - // Exposing trait Traits.SupportsScalarFunctionTrait - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName) - { - return __Trait15.ScalarFunction(scalarFunctionName); - } - - /// - /// This is used to query a scalar function. - /// - /// Name of the scalar function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder ScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName, System.Object functionArgumentValue) - { - return __Trait15.ScalarFunction(scalarFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsSqlQueriesTrait - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement) - { - return __Trait2.Sql(sqlStatement); - } - - /// - /// Creates a operation based on a raw SQL statement. - /// - /// The SQL statement. - /// The argument value. - /// SqlServerSqlCall. - public Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder Sql(System.String sqlStatement, System.Object argumentValue) - { - return __Trait2.Sql(sqlStatement, argumentValue); - } - - // Exposing trait Traits.SupportsTableFunctionTrait - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName) - { - return __Trait17.TableFunction(tableFunctionName); - } - - /// - /// This is used to query a table valued function. - /// - /// Name of the table function. - /// The function argument. - /// - public Tortuga.Chain.CommandBuilders.TableDbCommandBuilder TableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName, System.Object functionArgumentValue) - { - return __Trait17.TableFunction(tableFunctionName, functionArgumentValue); - } - - // Exposing trait Traits.SupportsTruncateTrait - - /// Truncates the specified table. - /// Name of the table to Truncate. - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate(Tortuga.Chain.SqlServer.SqlServerObjectName tableName) - { - return __Trait1.Truncate(tableName); - } - - /// Truncates the specified table. - /// This class used to determine which table to Truncate - /// The number of rows deleted or null if the database doesn't provide that information. - public Tortuga.Chain.ILink Truncate()where TObject : class - { - return __Trait1.Truncate(); - } - - // Exposing trait Traits.SupportsUpdateByKeyListTrait - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<AbstractCommand, AbstractParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, TKey key, Tortuga.Chain.UpdateOptions options = 0)where TKey : struct - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update a record by its primary key. - /// - /// The type of the t argument. - /// Name of the table. - /// The new values to use. - /// The key. - /// The options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - public Tortuga.Chain.CommandBuilders.SingleRowDbCommandBuilder UpdateByKey(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, System.String key, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKey(tableName, newValues, key, options); - } - - /// - /// Update multiple rows by key. - /// - /// The type of the t argument. - /// The type of the t key. - /// Name of the table. - /// The new values to use. - /// The keys. - /// Update options. - /// MultipleRowDbCommandBuilder<OleDbCommand, OleDbParameter>. - /// - public Tortuga.Chain.CommandBuilders.MultipleRowDbCommandBuilder UpdateByKeyList(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument newValues, System.Collections.Generic.IEnumerable keys, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait7.UpdateByKeyList(tableName, newValues, keys, options); - } - - // Exposing trait Traits.SupportsUpdateSet - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The argument value. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String updateExpression, System.Object? updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Name of the table. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Name of the table. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(tableName, updateExpression, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The argument for the update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, System.Object updateArgumentValue, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, updateArgumentValue, options); - } - - /// - /// Update multiple records using an update value. - /// - /// Class used to determine the table name. - /// The new values to use. - /// The options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.Object newValues, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(newValues, options); - } - - /// - /// Update multiple records using an update expression. - /// - /// Class used to determine the table name. - /// The update expression. - /// The update options. - /// Use .WithFilter to apply a WHERE clause. - public Tortuga.Chain.CommandBuilders.IUpdateSetDbCommandBuilder UpdateSet(System.String updateExpression, Tortuga.Chain.UpdateOptions options = 0) - { - return __Trait9.UpdateSet(updateExpression, options); - } - - // Exposing trait Traits.SupportsUpdateTrait - - /// - /// Update an object in the specified table. - /// - /// - /// The argument value. - /// The update options. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait6.Update(argumentValue, options); - } - - /// - /// Update an object in the specified table. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Update(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpdateOptions options = 0)where TArgument : class - { - return __Trait6.Update(tableName, argumentValue, options); - } - - // Exposing trait Traits.SupportsUpsertTrait - - /// - /// Creates a operation used to perform an "upsert" operation. - /// - /// - /// - /// - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(Tortuga.Chain.SqlServer.SqlServerObjectName tableName, TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(tableName, argumentValue, options); - } - - /// - /// Perform an insert or update operation as appropriate. - /// - /// - /// The argument value. - /// The options for how the insert/update occurs. - /// - public Tortuga.Chain.CommandBuilders.ObjectDbCommandBuilder Upsert(TArgument argumentValue, Tortuga.Chain.UpsertOptions options = 0)where TArgument : class - { - return __Trait13.Upsert(argumentValue, options); - } - - private partial Tortuga.Chain.ILink OnDeleteAll(Tortuga.Chain.SqlServer.SqlServerObjectName tableName ); - - private partial Tortuga.Chain.CommandBuilders.ProcedureDbCommandBuilder OnProcedure(Tortuga.Chain.SqlServer.SqlServerObjectName procedureName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.ScalarDbCommandBuilder OnScalarFunction(Tortuga.Chain.SqlServer.SqlServerObjectName scalarFunctionName, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.MultipleTableDbCommandBuilder OnSql(System.String sqlStatement, System.Object? argumentValue ); - - private partial Tortuga.Chain.CommandBuilders.TableDbCommandBuilder OnTableFunction(Tortuga.Chain.SqlServer.SqlServerObjectName tableFunctionName, System.Object? functionArgumentValue ); - - private partial Tortuga.Chain.ILink OnTruncate(Tortuga.Chain.SqlServer.SqlServerObjectName tableName ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnDeleteAll = OnDeleteAll; - __Trait0.DataSource = this; - __Trait1.OnTruncate = OnTruncate; - __Trait1.DataSource = this; - __Trait2.OnSql = OnSql; - __Trait3.DataSource = this; - __Trait4.DataSource = this; - __Trait5.DataSource = this; - __Trait6.DataSource = this; - __Trait7.DataSource = this; - __Trait8.DataSource = this; - __Trait9.DataSource = this; - __Trait10.DataSource = this; - __Trait11.DataSource = this; - __Trait12.DataSource = this; - __Trait13.DataSource = this; - __Trait14.DataSource = this; - __Trait15.OnScalarFunction = OnScalarFunction; - __Trait15.DataSource = this; - __Trait16.OnProcedure = OnProcedure; - __Trait16.DataSource = this; - __Trait17.OnTableFunction = OnTableFunction; - __Trait17.DataSource = this; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerOpenDataSource.cs deleted file mode 100644 index 75e5286c1..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerOpenDataSource.cs +++ /dev/null @@ -1,192 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class SqlServerOpenDataSource: Tortuga.Chain.DataSources.IOpenDataSource - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.OpenDataSourceTrait ___Trait0 = new(); - private Traits.OpenDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Exposing trait Traits.OpenDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.SqlClient.SqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.SqlClient.SqlTransaction? AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Closes the connection and transaction associated with this data source. - /// - public void Close() - { - __Trait0.Close(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SqlServer.SqlServerMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.SqlServerDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.SqlClient.SqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Data.SqlClient.SqlTransaction? m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Tries the commit the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryCommit() - { - return __Trait0.TryCommit(); - } - - /// - /// Tries the rollback the transaction associated with this data source. - /// - /// True if there was an open transaction associated with this data source, otherwise false. - public System.Boolean TryRollback() - { - return __Trait0.TryRollback(); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Modifies this data source to include the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SqlServer.SqlServerOpenDataSource OnOverride(System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnOverride = OnOverride; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource.cs deleted file mode 100644 index 38bcbe396..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource.cs +++ /dev/null @@ -1,181 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain.SqlServer -{ - partial class SqlServerTransactionalDataSource: Tortuga.Chain.DataSources.ITransactionalDataSource, Tortuga.Chain.DataSources.IOpenDataSource, System.IDisposable - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.TransactionalDataSourceTrait ___Trait0 = new(); - private Traits.TransactionalDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation System.IDisposable - void System.IDisposable.Dispose() - { - ((System.IDisposable)__Trait0).Dispose(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.IOpenDataSource - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IOpenDataSource.AssociatedConnection - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedConnection; - } - System.Data.Common.DbTransaction? Tortuga.Chain.DataSources.IOpenDataSource.AssociatedTransaction - { - get => ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).AssociatedTransaction; - } - void Tortuga.Chain.DataSources.IOpenDataSource.Close() - { - ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).Close(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryCommit() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryCommit(); - } - - System.Boolean Tortuga.Chain.DataSources.IOpenDataSource.TryRollback() - { - return ((Tortuga.Chain.DataSources.IOpenDataSource)__Trait0).TryRollback(); - } - - // Explicit interface implementation Tortuga.Chain.DataSources.ITransactionalDataSource - void Tortuga.Chain.DataSources.ITransactionalDataSource.Commit() - { - ((Tortuga.Chain.DataSources.ITransactionalDataSource)__Trait0).Commit(); - } - - // Exposing trait Traits.TransactionalDataSourceTrait - - /// - /// Returns the associated connection. - /// - /// The associated connection. - public System.Data.SqlClient.SqlConnection AssociatedConnection - { - get => __Trait0.AssociatedConnection; - } - /// - /// Returns the associated transaction. - /// - /// The associated transaction. - public System.Data.SqlClient.SqlTransaction AssociatedTransaction - { - get => __Trait0.AssociatedTransaction; - } - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// Commits the transaction and disposes the underlying connection. - /// - public void Commit() - { - __Trait0.Commit(); - } - - /// - /// Gets the database metadata. - /// - public override Tortuga.Chain.SqlServer.SqlServerMetadataCache DatabaseMetadata - { - get => __Trait0.DatabaseMetadata; - } - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - public void Dispose() - { - __Trait0.Dispose(); - } - - /// - /// Closes the current transaction and connection. If not committed, the transaction is rolled back. - /// - /// - protected virtual void Dispose(System.Boolean disposing) - { - __Trait0.Dispose(disposing); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - private Tortuga.Chain.SqlServerDataSource m_BaseDataSource - { - get => __Trait0.m_BaseDataSource; - init => __Trait0.m_BaseDataSource = value; - } - - private System.Data.SqlClient.SqlConnection m_Connection - { - get => __Trait0.m_Connection; - init => __Trait0.m_Connection = value; - } - - private System.Boolean m_Disposed - { - get => __Trait0.m_Disposed; - set => __Trait0.m_Disposed = value; - } - - private System.Data.SqlClient.SqlTransaction m_Transaction - { - get => __Trait0.m_Transaction; - init => __Trait0.m_Transaction = value; - } - /// - /// Rolls back the transaction and disposes the underlying connection. - /// - public void Rollback() - { - __Trait0.Rollback(); - } - - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.Container = this; - __Trait0.DisposableContainer = this as Traits.IHasOnDispose; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServerDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServerDataSource.cs deleted file mode 100644 index fbba70785..000000000 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/Generated/Tortuga.Shipwright/Tortuga.Shipwright.TraitGenerator/Tortuga.Chain.SqlServerDataSource.cs +++ /dev/null @@ -1,282 +0,0 @@ -//This file was generated by Tortuga Shipwright - -namespace Tortuga.Chain -{ - partial class SqlServerDataSource: Tortuga.Chain.DataSources.IRootDataSource, Traits.IHasExtensionCache - { - - private bool __TraitsRegistered; - - // These fields and/or properties hold the traits. They should not be referenced directly. - private Traits.RootDataSourceTrait ___Trait0 = new(); - private Traits.RootDataSourceTrait __Trait0 - { - get - { - if (!__TraitsRegistered) __RegisterTraits(); - return ___Trait0; - } - } - - // Explicit interface implementation Traits.IHasExtensionCache - System.Collections.Concurrent.ConcurrentDictionary Traits.IHasExtensionCache.ExtensionCache - { - get => ((Traits.IHasExtensionCache)__Trait0).ExtensionCache; - } - // Explicit interface implementation Tortuga.Chain.DataSources.IRootDataSource - Tortuga.Chain.DataSources.ITransactionalDataSource Tortuga.Chain.DataSources.IRootDataSource.BeginTransaction() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransaction(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.BeginTransactionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).BeginTransactionAsync(); - } - - System.Data.Common.DbConnection Tortuga.Chain.DataSources.IRootDataSource.CreateConnection() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnection(); - } - - System.Threading.Tasks.Task Tortuga.Chain.DataSources.IRootDataSource.CreateConnectionAsync() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateConnectionAsync(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource() - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.Common.DbConnection connection, System.Data.Common.DbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - Tortuga.Chain.DataSources.IOpenDataSource Tortuga.Chain.DataSources.IRootDataSource.CreateOpenDataSource(System.Data.IDbConnection connection, System.Data.IDbTransaction? transaction) - { - return ((Tortuga.Chain.DataSources.IRootDataSource)__Trait0).CreateOpenDataSource(connection, transaction); - } - - // Exposing trait Traits.RootDataSourceTrait - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource BeginTransaction() - { - return __Trait0.BeginTransaction(); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource BeginTransaction(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true) - { - return __Trait0.BeginTransaction(isolationLevel, forwardEvents); - } - - /// - /// Creates a new transaction. - /// - /// - /// - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync(System.Nullable isolationLevel = default, System.Boolean forwardEvents = true, System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.BeginTransactionAsync(isolationLevel, forwardEvents, cancellationToken); - } - - /// - /// Creates a new transaction. - /// - /// - /// The caller of this method is responsible for closing the transaction. - public System.Threading.Tasks.Task BeginTransactionAsync() - { - return __Trait0.BeginTransactionAsync(); - } - - /// - /// Gets or sets the cache to be used by this data source. The default is .NET's System.Runtime.Caching.MemoryCache. - /// - public override Tortuga.Chain.Core.ICacheAdapter Cache - { - get => __Trait0.Cache; - } - /// - /// The composed connection string. - /// - /// This is created and cached by a ConnectionStringBuilder. - internal System.String ConnectionString - { - get => __Trait0.ConnectionString; - } - /// - /// Creates and opens a new Access connection - /// - /// - /// The caller of this method is responsible for closing the connection. - public System.Data.SqlClient.SqlConnection CreateConnection() - { - return __Trait0.CreateConnection(); - } - - /// - /// Creates the connection asynchronous. - /// - /// The cancellation token. - /// - /// - /// The caller of this method is responsible for closing the connection. - /// - public System.Threading.Tasks.Task CreateConnectionAsync(System.Threading.CancellationToken cancellationToken = default) - { - return __Trait0.CreateConnectionAsync(cancellationToken); - } - - /// - /// Creates an open data source using the supplied connection and optional transaction. - /// - /// The connection to wrap. - /// The transaction to wrap. - /// IOpenDataSource. - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource CreateOpenDataSource(System.Data.SqlClient.SqlConnection connection, System.Data.SqlClient.SqlTransaction? transaction = default) - { - return __Trait0.CreateOpenDataSource(connection, transaction); - } - - /// - /// Creates an open data source with a new connection. - /// - /// WARNING: The caller of this method is responsible for closing the connection. - public Tortuga.Chain.SqlServer.SqlServerOpenDataSource CreateOpenDataSource() - { - return __Trait0.CreateOpenDataSource(); - } - - /// - /// The extension cache is used by extensions to store data source specific information. - /// - /// - /// The extension cache. - /// - protected override System.Collections.Concurrent.ConcurrentDictionary ExtensionCache - { - get => __Trait0.ExtensionCache; - } - - internal Tortuga.Chain.Core.ICacheAdapter m_Cache - { - get => __Trait0.m_Cache; - set => __Trait0.m_Cache = value; - } - /// - /// This object can be used to access the database connection string. - /// - private System.Data.SqlClient.SqlConnectionStringBuilder m_ConnectionBuilder - { - get => __Trait0.m_ConnectionBuilder; - init => __Trait0.m_ConnectionBuilder = value; - } - - internal System.Collections.Concurrent.ConcurrentDictionary m_ExtensionCache - { - get => __Trait0.m_ExtensionCache; - set => __Trait0.m_ExtensionCache = value; - } - /// - /// Tests the connection. - /// - public override void TestConnection() - { - __Trait0.TestConnection(); - } - - /// - /// Tests the connection asynchronously. - /// - /// - public override System.Threading.Tasks.Task TestConnectionAsync() - { - return __Trait0.TestConnectionAsync(); - } - - /// - /// Creates a new data source with the provided cache. - /// - /// The cache. - /// - public Tortuga.Chain.SqlServerDataSource WithCache(Tortuga.Chain.Core.ICacheAdapter cache) - { - return __Trait0.WithCache(cache); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServerDataSource WithRules(params Tortuga.Chain.AuditRules.AuditRule[] additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with additional audit rules. - /// - /// The additional rules. - /// - public Tortuga.Chain.SqlServerDataSource WithRules(System.Collections.Generic.IEnumerable additionalRules) - { - return __Trait0.WithRules(additionalRules); - } - - /// - /// Creates a new data source with the indicated user. - /// - /// The user value. - /// - /// - /// This is used in conjunction with audit rules. - /// - public Tortuga.Chain.SqlServerDataSource WithUser(System.Object? userValue) - { - return __Trait0.WithUser(userValue); - } - - private partial Tortuga.Chain.SqlServer.SqlServerTransactionalDataSource OnBeginTransaction(System.Nullable isolationLevel, System.Boolean forwardEvents ); - - private partial System.Threading.Tasks.Task OnBeginTransactionAsync(System.Nullable isolationLevel, System.Boolean forwardEvents, System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SqlServerDataSource OnCloneWithOverrides(Tortuga.Chain.Core.ICacheAdapter? cache, System.Collections.Generic.IEnumerable? additionalRules, System.Object? userValue ); - - private partial System.Data.SqlClient.SqlConnection OnCreateConnection( ); - - private partial System.Threading.Tasks.Task OnCreateConnectionAsync(System.Threading.CancellationToken cancellationToken ); - - private partial Tortuga.Chain.SqlServer.SqlServerOpenDataSource OnCreateOpenDataSource(System.Data.SqlClient.SqlConnection connection, System.Data.SqlClient.SqlTransaction? transaction ); - - private void __RegisterTraits() - { - __TraitsRegistered = true; - __Trait0.OnBeginTransaction = OnBeginTransaction; - __Trait0.OnBeginTransactionAsync = OnBeginTransactionAsync; - __Trait0.OnCreateConnection = OnCreateConnection; - __Trait0.OnCreateConnectionAsync = OnCreateConnectionAsync; - __Trait0.OnCreateOpenDataSource = OnCreateOpenDataSource; - __Trait0.OnCloneWithOverrides = OnCloneWithOverrides; - } - - } -} diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/Tortuga.Chain.SqlServer.csproj b/Tortuga.Chain/Tortuga.Chain.SqlServer/Tortuga.Chain.SqlServer.csproj index 92dded9e2..fc5dbec5f 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/Tortuga.Chain.SqlServer.csproj +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/Tortuga.Chain.SqlServer.csproj @@ -10,7 +10,7 @@ Tortuga Chain true - 4.0.2 + 4.1.0 MIT @@ -56,7 +56,7 @@ - + @@ -76,7 +76,7 @@ - true + Generated @@ -84,7 +84,7 @@ - + diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/AbstractSqlServerMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/AbstractSqlServerMetadataCache.cs index 81fe0d698..fa7d74a17 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/AbstractSqlServerMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/AbstractSqlServerMetadataCache.cs @@ -4,292 +4,291 @@ using Tortuga.Anchor; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer -{ +namespace Tortuga.Chain.SqlServer; + #if SQL_SERVER_SDS || SQL_SERVER_MDS - /// Class AbstractSqlServerMetadataCache. - public abstract class AbstractSqlServerMetadataCache : DatabaseMetadataCache +/// Class AbstractSqlServerMetadataCache. +public abstract class AbstractSqlServerMetadataCache : DatabaseMetadataCache #elif SQL_SERVER_OLEDB - /// Class AbstractSqlServerMetadataCache. - public abstract class AbstractOleDbSqlServerMetadataCache : OleDbDatabaseMetadataCache +/// Class AbstractSqlServerMetadataCache. +public abstract class AbstractOleDbSqlServerMetadataCache : OleDbDatabaseMetadataCache #endif +{ + /// + /// Gets the metadata for a table. + /// + /// Name of the table. + /// + public override sealed TableOrViewMetadata GetTableOrView(SqlServerObjectName tableName) { - /// - /// Gets the metadata for a table. - /// - /// Name of the table. - /// - public override sealed TableOrViewMetadata GetTableOrView(SqlServerObjectName tableName) - { - return OnGetTableOrView(tableName); - } - - //C# doesn't allow us to change the return type so we're using this as a thunk. - internal abstract TableOrViewMetadata OnGetTableOrView(SqlServerObjectName tableName); + return OnGetTableOrView(tableName); } + //C# doesn't allow us to change the return type so we're using this as a thunk. + internal abstract TableOrViewMetadata OnGetTableOrView(SqlServerObjectName tableName); +} + #if SQL_SERVER_SDS || SQL_SERVER_MDS - partial class SqlServerMetadataCache : AbstractSqlServerMetadataCache +partial class SqlServerMetadataCache : AbstractSqlServerMetadataCache #elif SQL_SERVER_OLEDB - partial class OleDbSqlServerMetadataCache : AbstractOleDbSqlServerMetadataCache +partial class OleDbSqlServerMetadataCache : AbstractOleDbSqlServerMetadataCache #endif - { - internal readonly DbConnectionStringBuilder m_ConnectionBuilder; +{ + internal readonly DbConnectionStringBuilder m_ConnectionBuilder; - internal readonly ConcurrentDictionary> m_ScalarFunctions = new ConcurrentDictionary>(); - internal readonly ConcurrentDictionary> m_StoredProcedures = new ConcurrentDictionary>(); + internal readonly ConcurrentDictionary> m_ScalarFunctions = new(); + internal readonly ConcurrentDictionary> m_StoredProcedures = new(); - internal readonly ConcurrentDictionary> m_TableFunctions = new ConcurrentDictionary>(); + internal readonly ConcurrentDictionary> m_TableFunctions = new(); - internal readonly ConcurrentDictionary> m_Tables = new ConcurrentDictionary>(); + internal readonly ConcurrentDictionary> m_Tables = new(); - internal readonly ConcurrentDictionary> m_TypeTableMap = new ConcurrentDictionary>(); + internal readonly ConcurrentDictionary> m_TypeTableMap = new(); - internal readonly ConcurrentDictionary> m_UserDefinedTableTypes = new ConcurrentDictionary>(); + internal readonly ConcurrentDictionary> m_UserDefinedTableTypes = new(); - internal string? m_DatabaseName; - internal string? m_DefaultSchema; + internal string? m_DatabaseName; + internal string? m_DefaultSchema; - /// - /// Gets the metadata for a scalar function. - /// - /// Name of the scalar function. - /// Null if the object could not be found. - public override ScalarFunctionMetadata GetScalarFunction(SqlServerObjectName scalarFunctionName) - { - return m_ScalarFunctions.GetOrAdd(scalarFunctionName, GetScalarFunctionInternal); - } + /// + /// Gets the metadata for a scalar function. + /// + /// Name of the scalar function. + /// Null if the object could not be found. + public override ScalarFunctionMetadata GetScalarFunction(SqlServerObjectName scalarFunctionName) + { + return m_ScalarFunctions.GetOrAdd(scalarFunctionName, GetScalarFunctionInternal); + } - /// - /// Gets the scalar functions that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetScalarFunctions() - { - return m_ScalarFunctions.GetValues(); - } + /// + /// Gets the scalar functions that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all scalar functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetScalarFunctions() + { + return m_ScalarFunctions.GetValues(); + } - /// - /// Gets the stored procedure's metadata. - /// - /// Name of the procedure. - /// Null if the object could not be found. - public override StoredProcedureMetadata GetStoredProcedure(SqlServerObjectName procedureName) - { - return m_StoredProcedures.GetOrAdd(procedureName, GetStoredProcedureInternal); - } + /// + /// Gets the stored procedure's metadata. + /// + /// Name of the procedure. + /// Null if the object could not be found. + public override StoredProcedureMetadata GetStoredProcedure(SqlServerObjectName procedureName) + { + return m_StoredProcedures.GetOrAdd(procedureName, GetStoredProcedureInternal); + } - /// - /// Gets the stored procedures that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetStoredProcedures() - { - return m_StoredProcedures.GetValues(); - } + /// + /// Gets the stored procedures that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all stored procedures were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetStoredProcedures() + { + return m_StoredProcedures.GetValues(); + } - /// - /// Gets the metadata for a table function. - /// - /// Name of the table function. - /// Null if the object could not be found. - public override TableFunctionMetadata GetTableFunction(SqlServerObjectName tableFunctionName) - { - return m_TableFunctions.GetOrAdd(tableFunctionName, GetTableFunctionInternal); - } + /// + /// Gets the metadata for a table function. + /// + /// Name of the table function. + /// Null if the object could not be found. + public override TableFunctionMetadata GetTableFunction(SqlServerObjectName tableFunctionName) + { + return m_TableFunctions.GetOrAdd(tableFunctionName, GetTableFunctionInternal); + } - /// - /// Gets the table-valued functions that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetTableFunctions() - { - return m_TableFunctions.GetValues(); - } + /// + /// Gets the table-valued functions that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetTableFunctions() + { + return m_TableFunctions.GetValues(); + } - /// - /// Gets the tables and views that were loaded by this cache. - /// - /// - /// - /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - /// - public override IReadOnlyCollection> GetTablesAndViews() - { - return m_Tables.GetValues(); - } + /// + /// Gets the tables and views that were loaded by this cache. + /// + /// + /// + /// Call Preload before invoking this method to ensure that all tables and views were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + /// + public override IReadOnlyCollection> GetTablesAndViews() + { + return m_Tables.GetValues(); + } - /// - /// Gets the metadata for a user defined type. - /// - /// Name of the type. - /// UserDefinedTableTypeMetadata<SqlServerObjectName, SqlDbType>. - public override UserDefinedTableTypeMetadata GetUserDefinedTableType(SqlServerObjectName typeName) - { - return m_UserDefinedTableTypes.GetOrAdd(typeName, GetUserDefinedTableTypeInternal); - } + /// + /// Gets the metadata for a user defined type. + /// + /// Name of the type. + /// UserDefinedTableTypeMetadata<SqlServerObjectName, SqlDbType>. + public override UserDefinedTableTypeMetadata GetUserDefinedTableType(SqlServerObjectName typeName) + { + return m_UserDefinedTableTypes.GetOrAdd(typeName, GetUserDefinedTableTypeInternal); + } - /// - /// Gets the table-valued functions that were loaded by this cache. - /// - /// ICollection<UserDefinedTableTypeMetadata<SqlServerObjectName, SqlDbType>>. - /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. - public override IReadOnlyCollection> GetUserDefinedTableTypes() - { - return m_UserDefinedTableTypes.GetValues(); - } + /// + /// Gets the table-valued functions that were loaded by this cache. + /// + /// ICollection<UserDefinedTableTypeMetadata<SqlServerObjectName, SqlDbType>>. + /// Call Preload before invoking this method to ensure that all table-valued functions were loaded from the database's schema. Otherwise only the objects that were actually used thus far will be returned. + public override IReadOnlyCollection> GetUserDefinedTableTypes() + { + return m_UserDefinedTableTypes.GetValues(); + } - /// - /// Preloads all of the metadata for this data source. - /// - public override void Preload() - { - PreloadTables(); - PreloadViews(); - PreloadStoredProcedures(); - PreloadTableFunctions(); - PreloadUserDefinedTableTypes(); - PreloadScalarFunctions(); - } + /// + /// Preloads all of the metadata for this data source. + /// + public override void Preload() + { + PreloadTables(); + PreloadViews(); + PreloadStoredProcedures(); + PreloadTableFunctions(); + PreloadUserDefinedTableTypes(); + PreloadScalarFunctions(); + } - /// - /// Resets the metadata cache, clearing out all cached metadata. - /// - public override void Reset() - { - m_StoredProcedures.Clear(); - m_TableFunctions.Clear(); - m_Tables.Clear(); - m_TypeTableMap.Clear(); - m_UserDefinedTableTypes.Clear(); - m_ScalarFunctions.Clear(); - m_ScalarFunctions.Clear(); - m_DefaultSchema = null; - } + /// + /// Resets the metadata cache, clearing out all cached metadata. + /// + public override void Reset() + { + m_StoredProcedures.Clear(); + m_TableFunctions.Clear(); + m_Tables.Clear(); + m_TypeTableMap.Clear(); + m_UserDefinedTableTypes.Clear(); + m_ScalarFunctions.Clear(); + m_ScalarFunctions.Clear(); + m_DefaultSchema = null; + } - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - internal static void AdjustTypeDetails(string typeName, ref int? maxLength, ref int? precision, ref int? scale, out string fullTypeName) + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + internal static void AdjustTypeDetails(string typeName, ref int? maxLength, ref int? precision, ref int? scale, out string fullTypeName) + { + switch (typeName) { - switch (typeName) - { - case "bigint": - case "bit": - case "date": - case "datetime": - case "timestamp": - case "tinyint": - case "uniqueidentifier": - case "smallint": - case "sql_variant": - case "float": - case "int": - maxLength = null; - precision = null; - scale = null; - fullTypeName = typeName; - break; - - case "binary": - case "char": - precision = null; - scale = null; + case "bigint": + case "bit": + case "date": + case "datetime": + case "timestamp": + case "tinyint": + case "uniqueidentifier": + case "smallint": + case "sql_variant": + case "float": + case "int": + maxLength = null; + precision = null; + scale = null; + fullTypeName = typeName; + break; + + case "binary": + case "char": + precision = null; + scale = null; + fullTypeName = $"{typeName}({maxLength})"; + break; + + case "datetime2": + case "datetimeoffset": + case "time": + maxLength = null; + precision = null; + fullTypeName = $"{typeName}({scale})"; + break; + + case "numeric": + case "decimal": + fullTypeName = $"{typeName}({precision},{scale})"; + break; + + case "nchar": + maxLength = maxLength / 2; + precision = null; + scale = null; + fullTypeName = $"nchar({maxLength})"; + break; + + case "nvarchar": + maxLength = maxLength / 2; + precision = null; + scale = null; + if (maxLength > 0) + fullTypeName = $"nvarchar({maxLength})"; + else + fullTypeName = $"nvarchar(max)"; + break; + + case "varbinary": + case "varchar": + precision = null; + scale = null; + if (maxLength > 0) fullTypeName = $"{typeName}({maxLength})"; - break; - - case "datetime2": - case "datetimeoffset": - case "time": - maxLength = null; - precision = null; - fullTypeName = $"{typeName}({scale})"; - break; - - case "numeric": - case "decimal": - fullTypeName = $"{typeName}({precision},{scale})"; - break; - - case "nchar": - maxLength = maxLength / 2; - precision = null; - scale = null; - fullTypeName = $"nchar({maxLength})"; - break; - - case "nvarchar": - maxLength = maxLength / 2; - precision = null; - scale = null; - if (maxLength > 0) - fullTypeName = $"nvarchar({maxLength})"; - else - fullTypeName = $"nvarchar(max)"; - break; - - case "varbinary": - case "varchar": - precision = null; - scale = null; - if (maxLength > 0) - fullTypeName = $"{typeName}({maxLength})"; - else - fullTypeName = $"{typeName}(max)"; - break; - - default: - if (maxLength <= 0) - maxLength = 0; - if (precision <= 0) - precision = 0; - if (scale <= 0) - scale = 0; - fullTypeName = typeName; - break; - } - } - - /// - /// Parse a string and return the database specific representation of the object name. - /// - /// The schema. - /// The name. - /// SqlServerObjectName. - protected override SqlServerObjectName ParseObjectName(string? schema, string name) - { - if (schema == null) - return new SqlServerObjectName(name); - return new SqlServerObjectName(schema, name); + else + fullTypeName = $"{typeName}(max)"; + break; + + default: + if (maxLength <= 0) + maxLength = 0; + if (precision <= 0) + precision = 0; + if (scale <= 0) + scale = 0; + fullTypeName = typeName; + break; } + } - internal override TableOrViewMetadata OnGetTableOrView(SqlServerObjectName tableName) - { - return GetTableOrView(tableName); - } + /// + /// Parse a string and return the database specific representation of the object name. + /// + /// The schema. + /// The name. + /// SqlServerObjectName. + protected override SqlServerObjectName ParseObjectName(string? schema, string name) + { + if (schema == null) + return new SqlServerObjectName(name); + return new SqlServerObjectName(schema, name); + } - /// - /// Gets the maximum number of parameters in a single SQL batch. - /// - /// The maximum number of parameters. - /// Note that the documentation says 2100, but you need to subtract one for the SQL statement itself. https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server?view=sql-server-ver15 - public override int? MaxParameters => 2099; - - /// - /// Get the maximum number of rows in a single SQL statement's Values clause. - /// - public override int? MaxRowsPerValuesClause => 1000; + internal override TableOrViewMetadata OnGetTableOrView(SqlServerObjectName tableName) + { + return GetTableOrView(tableName); } -} + + /// + /// Gets the maximum number of parameters in a single SQL batch. + /// + /// The maximum number of parameters. + /// Note that the documentation says 2100, but you need to subtract one for the SQL statement itself. https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server?view=sql-server-ver15 + public override int? MaxParameters => 2099; + + /// + /// Get the maximum number of rows in a single SQL statement's Values clause. + /// + public override int? MaxRowsPerValuesClause => 1000; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Appenders/NotifyChangeAppender`1.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Appenders/NotifyChangeAppender`1.cs index 978fc9864..f0955919b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Appenders/NotifyChangeAppender`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Appenders/NotifyChangeAppender`1.cs @@ -2,39 +2,37 @@ using Tortuga.Chain.Appenders; using Tortuga.Chain.Core; -namespace Tortuga.Chain.SqlServer.Appenders +namespace Tortuga.Chain.SqlServer.Appenders; + +internal class NotifyChangeAppender : Appender { - internal class NotifyChangeAppender : Appender - { - readonly OnChangeEventHandler m_EventHandler; + readonly OnChangeEventHandler m_EventHandler; - /// - /// Initializes a new instance of the class. - /// - /// The previous link. - /// The event handler to fire when then associated SQL Dependency is fired.. - public NotifyChangeAppender(ILink previousLink, OnChangeEventHandler eventHandler) - : base(previousLink) - { - if (previousLink == null) - throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); - if (eventHandler == null) - throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); + /// + /// Initializes a new instance of the class. + /// + /// The previous link. + /// The event handler to fire when then associated SQL Dependency is fired.. + public NotifyChangeAppender(ILink previousLink, OnChangeEventHandler eventHandler) + : base(previousLink) + { + if (previousLink == null) + throw new ArgumentNullException(nameof(previousLink), $"{nameof(previousLink)} is null."); + if (eventHandler == null) + throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); - m_EventHandler = eventHandler; - } + m_EventHandler = eventHandler; + } - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "NotifyChangeAppender")] - protected override void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) - { - if (e == null) - throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "NotifyChangeAppender")] + protected override void OnExecutionTokenPrepared(ExecutionTokenPreparedEventArgs e) + { + if (e == null) + throw new ArgumentNullException(nameof(e), $"{nameof(e)} is null."); - var token = e.ExecutionToken as SqlServerCommandExecutionToken; - if (token == null) - throw new NotSupportedException($"This type of command builder does not support SQL Dependency, which is required for the {nameof(NotifyChangeAppender)}."); - token.AddChangeListener(m_EventHandler); - } + var token = e.ExecutionToken as SqlServerCommandExecutionToken; + if (token == null) + throw new NotSupportedException($"This type of command builder does not support SQL Dependency, which is required for the {nameof(NotifyChangeAppender)}."); + token.AddChangeListener(m_EventHandler); } } - diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsApproximateCount.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsApproximateCount.cs index 5c4a709f2..ba6a6d289 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsApproximateCount.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsApproximateCount.cs @@ -1,9 +1,8 @@ -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +interface ISupportsApproximateCount { - interface ISupportsApproximateCount - { - ILink AsCountApproximate(string columnName); + ILink AsCountApproximate(string columnName); - ILink AsCountApproximate(); - } + ILink AsCountApproximate(); } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsChangeListener.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsChangeListener.cs index 940684f01..9ae0aa9fc 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsChangeListener.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/ISupportsChangeListener.cs @@ -1,25 +1,24 @@ using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// This is applied to command builders that support SqlDependency operations. +/// +internal interface ISupportsChangeListener { /// - /// This is applied to command builders that support SqlDependency operations. + /// Prepares the command for execution by generating any necessary SQL. /// - internal interface ISupportsChangeListener - { - /// - /// Waits for change in the data that is returned by this operation. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task that can be waited for. - /// This requires the use of SQL Dependency - Task WaitForChange(CancellationToken cancellationToken, object? state = null); + /// The materializer. + SqlServerCommandExecutionToken Prepare(Materializer materializer); - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - SqlServerCommandExecutionToken Prepare(Materializer materializer); - } + /// + /// Waits for change in the data that is returned by this operation. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task that can be waited for. + /// This requires the use of SQL Dependency + Task WaitForChange(CancellationToken cancellationToken, object? state = null); } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteObject.cs index 6c2a83c09..3992bc6d1 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteObject.cs @@ -2,61 +2,57 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerDeleteObject. +/// +internal sealed class SqlServerDeleteObject : SqlServerObjectCommand + where TArgument : class { + readonly DeleteOptions m_Options; + /// - /// Class SqlServerDeleteObject. + /// Initializes a new instance of the class. /// - internal sealed class SqlServerDeleteObject : SqlServerObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public SqlServerDeleteObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, DeleteOptions options) : base(dataSource, tableName, argumentValue) { - readonly DeleteOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public SqlServerDeleteObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, DeleteOptions options) : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); - - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; - - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - sql.Append(header); - sql.Append("DELETE FROM " + Table.Name.ToQuotedString()); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); - sqlBuilder.BuildWhereClause(sql, " WHERE ", null); - sql.Append(";"); - sql.Append(footer); - - return new SqlServerCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); - } + m_Options = options; + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); + + var sql = new StringBuilder(); + + sqlBuilder.UseTableVariable(Table, out var header, out var intoClause, out var footer); + sql.Append(header); + sql.Append("DELETE FROM " + Table.Name.ToQuotedString()); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); + sqlBuilder.BuildWhereClause(sql, " WHERE ", null); + sql.Append(";"); + sql.Append(footer); + + return new SqlServerCommandExecutionToken(DataSource, "Delete from " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckDeleteRowCount(m_Options); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteSet.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteSet.cs index 09ecb357b..95da06178 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerDeleteSet.cs @@ -4,142 +4,141 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerDeleteSet. +/// +internal sealed class SqlServerDeleteSet : MultipleRowDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly int? m_ExpectedRowCount; + readonly FilterOptions m_FilterOptions; + readonly object? m_FilterValue; + readonly DeleteOptions m_Options; + readonly IEnumerable? m_Parameters; + + readonly SqlServerTableOrViewMetadata m_Table; + readonly string? m_WhereClause; + /// - /// Class SqlServerDeleteSet. + /// Initializes a new instance of the class. /// - internal sealed class SqlServerDeleteSet : MultipleRowDbCommandBuilder + /// The data source. + /// Name of the table. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public SqlServerDeleteSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) { - readonly IEnumerable? m_Parameters; - - readonly SqlServerTableOrViewMetadata m_Table; - readonly string? m_WhereClause; - readonly object? m_ArgumentValue; - readonly object? m_FilterValue; - readonly FilterOptions m_FilterOptions; - readonly DeleteOptions m_Options; - readonly int? m_ExpectedRowCount; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public SqlServerDeleteSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string whereClause, IEnumerable parameters, int? expectedRowCount, DeleteOptions options) : base(dataSource) - { - if (options.HasFlag(DeleteOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_Parameters = parameters; - m_Options = options; - m_ExpectedRowCount = expectedRowCount; - } + if (options.HasFlag(DeleteOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_Parameters = parameters; + m_Options = options; + m_ExpectedRowCount = expectedRowCount; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The where clause. - /// The argument value. - public SqlServerDeleteSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string whereClause, object? argumentValue) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The where clause. + /// The argument value. + public SqlServerDeleteSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string whereClause, object? argumentValue) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The filter value. - /// The options. - public SqlServerDeleteSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - } + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The filter value. + /// The options. + public SqlServerDeleteSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object filterValue, FilterOptions filterOptions) : base(dataSource) + { + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + List parameters; + var sql = new StringBuilder(); - public override CommandExecutionToken Prepare(Materializer materializer) + sqlBuilder.UseTableVariable(m_Table, out var header, out var intoClause, out var footer); + + sql.Append(header); + sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); + if (m_FilterValue != null) { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - List parameters; - var sql = new StringBuilder(); - - sqlBuilder.UseTableVariable(m_Table, out var header, out var intoClause, out var footer); - - sql.Append(header); - sql.Append("DELETE FROM " + m_Table.Name.ToQuotedString()); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Deleted.", intoClause); - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - parameters = sqlBuilder.GetParameters(); - } - sql.Append(";"); - sql.Append(footer); - - if (m_Parameters != null) - parameters.AddRange(m_Parameters); - - return new SqlServerCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + + parameters = sqlBuilder.GetParameters(); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - return m_Table.Columns.TryGetColumn(columnName); + parameters = sqlBuilder.GetParameters(); } + sql.Append(";"); + sql.Append(footer); - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + if (m_Parameters != null) + parameters.AddRange(m_Parameters); + + return new SqlServerCommandExecutionToken(DataSource, "Delete from " + m_Table.Name, sql.ToString(), parameters).CheckDeleteRowCount(m_Options, m_ExpectedRowCount); } -} + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatch.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatch.cs index 676098ae7..2a199bcd0 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatch.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatch.cs @@ -5,103 +5,102 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders -{ - /// - /// Class SqlServerInsertBatchTable is when using a values clause with an array of rows. - /// - internal class SqlServerInsertBatch : MultipleRowDbCommandBuilder - where TObject : class - { - readonly InsertOptions m_Options; - readonly IReadOnlyList m_SourceList; - readonly TableOrViewMetadata m_Table; - - public SqlServerInsertBatch(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, IEnumerable objects, InsertOptions options) : base(dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); +namespace Tortuga.Chain.SqlServer.CommandBuilders; - var sourceList = objects.AsReadOnlyList(); - - if (sourceList == null || sourceList.Count == 0) - throw new ArgumentException($"{nameof(objects)} is null or empty.", nameof(objects)); +/// +/// Class SqlServerInsertBatchTable is when using a values clause with an array of rows. +/// +internal class SqlServerInsertBatch : MultipleRowDbCommandBuilder + where TObject : class +{ + readonly InsertOptions m_Options; + readonly IReadOnlyList m_SourceList; + readonly TableOrViewMetadata m_Table; - if (sourceList.Count > 1000) - throw new ArgumentException($"{nameof(objects)}.Count exceeds SQL Server's row count limit of 1000. Supply a table type, break the call into batches of 1000, use InsertMultipleBatch, or use BulkInsert.", nameof(objects)); + public SqlServerInsertBatch(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, IEnumerable objects, InsertOptions options) : base(dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - m_SourceList = sourceList; - m_Options = options; - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - } + var sourceList = objects.AsReadOnlyList(); - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + if (sourceList == null || sourceList.Count == 0) + throw new ArgumentException($"{nameof(objects)} is null or empty.", nameof(objects)); - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + if (sourceList.Count > 1000) + throw new ArgumentException($"{nameof(objects)}.Count exceeds SQL Server's row count limit of 1000. Supply a table type, break the call into batches of 1000, use InsertMultipleBatch, or use BulkInsert.", nameof(objects)); - //This sets up the sqlBuilder. We're not actually going to build the parameters now - sqlBuilder.ApplyArgumentValue(DataSource, m_SourceList[0], m_Options); + m_SourceList = sourceList; + m_Options = options; + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + } - var sql = new StringBuilder(); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} ON;"); + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {m_Table.Name.ToQuotedString()} (", null, ")", identityInsert); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", null); - sql.AppendLine("VALUES"); + //This sets up the sqlBuilder. We're not actually going to build the parameters now + sqlBuilder.ApplyArgumentValue(DataSource, m_SourceList[0], m_Options); - var parameters = new List(); - for (var i = 0; i < m_SourceList.Count; i++) - { - var parameterSuffix = "_" + i; - var footer = (i == m_SourceList.Count - 1) ? ");" : "),"; + var sql = new StringBuilder(); - sqlBuilder.OverrideArgumentValue(DataSource, AuditRules.OperationTypes.Insert, m_SourceList[i]); - sqlBuilder.BuildValuesClause(sql, "(", footer, identityInsert, parameterSuffix, parameters, Utilities.ParameterBuilderCallback); - } + bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} ON;"); - var maxParams = DataSource.DatabaseMetadata.MaxParameters!.Value; - if (parameters.Count > maxParams) - { - var parametersPerRow = parameters.Count / m_SourceList.Count; - var maxRows = maxParams / parametersPerRow; - throw new InvalidOperationException($"Batch insert exceeds SQL Server's parameter limit of {DataSource.DatabaseMetadata.MaxParameters}. Supply a table type, break the call into batches of {maxRows}, use InsertMultipleBatch, or use BulkInsert"); - } + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {m_Table.Name.ToQuotedString()} (", null, ")", identityInsert); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", null); + sql.AppendLine("VALUES"); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} OFF;"); + var parameters = new List(); + for (var i = 0; i < m_SourceList.Count; i++) + { + var parameterSuffix = "_" + i; + var footer = (i == m_SourceList.Count - 1) ? ");" : "),"; - return new SqlServerCommandExecutionToken(DataSource, "Insert batch into " + m_Table.Name, sql.ToString(), parameters); + sqlBuilder.OverrideArgumentValue(DataSource, AuditRules.OperationTypes.Insert, m_SourceList[i]); + sqlBuilder.BuildValuesClause(sql, "(", footer, identityInsert, parameterSuffix, parameters, Utilities.ParameterBuilderCallback); } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + var maxParams = DataSource.DatabaseMetadata.MaxParameters!.Value; + if (parameters.Count > maxParams) { - return m_Table.Columns.TryGetColumn(columnName); + var parametersPerRow = parameters.Count / m_SourceList.Count; + var maxRows = maxParams / parametersPerRow; + throw new InvalidOperationException($"Batch insert exceeds SQL Server's parameter limit of {DataSource.DatabaseMetadata.MaxParameters}. Supply a table type, break the call into batches of {maxRows}, use InsertMultipleBatch, or use BulkInsert"); } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} OFF;"); + + return new SqlServerCommandExecutionToken(DataSource, "Insert batch into " + m_Table.Name, sql.ToString(), parameters); } -} + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatchTable.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatchTable.cs index e38d8dae3..7e8184fbf 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatchTable.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBatchTable.cs @@ -6,91 +6,90 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders -{ - /// - /// Class SqlServerInsertBatchTable is when a table-type parameter is provided. - /// - internal class SqlServerInsertBatchTable : MultipleRowDbCommandBuilder - { - readonly InsertOptions m_Options; +namespace Tortuga.Chain.SqlServer.CommandBuilders; - readonly object m_Source; - readonly TableOrViewMetadata m_Table; - readonly UserDefinedTableTypeMetadata m_TableType; +/// +/// Class SqlServerInsertBatchTable is when a table-type parameter is provided. +/// +internal class SqlServerInsertBatchTable : MultipleRowDbCommandBuilder +{ + readonly InsertOptions m_Options; - public SqlServerInsertBatchTable(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, DataTable dataTable, SqlServerObjectName tableTypeName, InsertOptions options) : base(dataSource) - { - m_Source = dataTable; - m_Options = options; - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_TableType = dataSource.DatabaseMetadata.GetUserDefinedTableType(tableTypeName); - } + readonly object m_Source; + readonly TableOrViewMetadata m_Table; + readonly UserDefinedTableTypeMetadata m_TableType; - public SqlServerInsertBatchTable(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, DbDataReader dataReader, SqlServerObjectName tableTypeName, InsertOptions options) : base(dataSource) - { - m_Source = dataReader; - m_Options = options; - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_TableType = dataSource.DatabaseMetadata.GetUserDefinedTableType(tableTypeName); - } + public SqlServerInsertBatchTable(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, DataTable dataTable, SqlServerObjectName tableTypeName, InsertOptions options) : base(dataSource) + { + m_Source = dataTable; + m_Options = options; + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_TableType = dataSource.DatabaseMetadata.GetUserDefinedTableType(tableTypeName); + } - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + public SqlServerInsertBatchTable(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, DbDataReader dataReader, SqlServerObjectName tableTypeName, InsertOptions options) : base(dataSource) + { + m_Source = dataReader; + m_Options = options; + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_TableType = dataSource.DatabaseMetadata.GetUserDefinedTableType(tableTypeName); + } - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyTableType(DataSource, OperationTypes.Insert, m_TableType.Columns); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sql = new StringBuilder(); + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyTableType(DataSource, OperationTypes.Insert, m_TableType.Columns); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} ON;"); + var sql = new StringBuilder(); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {m_Table.Name.ToQuotedString()} (", null, ")", identityInsert); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", null); - sqlBuilder.BuildSelectTvpForInsertClause(sql, " SELECT ", null, " FROM @ValuesParameter ", identityInsert); - sql.Append(";"); + bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} ON;"); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} OFF;"); + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {m_Table.Name.ToQuotedString()} (", null, ")", identityInsert); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", null); + sqlBuilder.BuildSelectTvpForInsertClause(sql, " SELECT ", null, " FROM @ValuesParameter ", identityInsert); + sql.Append(";"); - var parameters = sqlBuilder.GetParameters(); - parameters.Add(new SqlParameter() - { - ParameterName = "@ValuesParameter", - Value = m_Source, - SqlDbType = SqlDbType.Structured, - TypeName = m_TableType.Name.ToQuotedString() - }); - return new SqlServerCommandExecutionToken(DataSource, "Insert batch into " + m_Table.Name, sql.ToString(), parameters); - } + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {m_Table.Name.ToQuotedString()} OFF;"); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + var parameters = sqlBuilder.GetParameters(); + parameters.Add(new SqlParameter() { - return m_Table.Columns.TryGetColumn(columnName); - } + ParameterName = "@ValuesParameter", + Value = m_Source, + SqlDbType = SqlDbType.Structured, + TypeName = m_TableType.Name.ToQuotedString() + }); + return new SqlServerCommandExecutionToken(DataSource, "Insert batch into " + m_Table.Name, sql.ToString(), parameters); + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); } -} + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBulk.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBulk.cs index 246a55729..9e2a1950b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBulk.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertBulk.cs @@ -2,186 +2,185 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// This class is used to perform bulk inserts +/// +/// +public sealed class SqlServerInsertBulk : DbOperationBuilder { + readonly SqlServerDataSourceBase m_DataSource; + readonly IDataReader m_Source; + readonly TableOrViewMetadata m_Table; + int? m_BatchSize; + bool m_EnableStreaming; + EventHandler? m_EventHandler; + int? m_NotifyAfter; + SqlBulkCopyOptions m_Options; + + internal SqlServerInsertBulk(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, DataTable dataTable) : base(dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (dataTable == null) + throw new ArgumentNullException(nameof(dataTable), $"{nameof(dataTable)} is null."); + + m_DataSource = dataSource; + m_Source = dataTable.CreateDataReader(); + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + if (!m_Table.IsTable) + throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); + } + + internal SqlServerInsertBulk(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, IDataReader dataReader) : base(dataSource) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + if (dataReader == null) + throw new ArgumentNullException(nameof(dataReader), $"{nameof(dataReader)} is null."); + + m_DataSource = dataSource; + m_Source = dataReader; + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + if (!m_Table.IsTable) + throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); + } + /// - /// This class is used to perform bulk inserts + /// Prepares the command for execution by generating any necessary SQL. /// - /// - public sealed class SqlServerInsertBulk : DbOperationBuilder + /// ExecutionToken<TCommand>. + public override OperationExecutionToken Prepare() { - readonly SqlServerDataSourceBase m_DataSource; - SqlBulkCopyOptions m_Options; - readonly IDataReader m_Source; - readonly TableOrViewMetadata m_Table; - int? m_BatchSize; - bool m_EnableStreaming; - EventHandler? m_EventHandler; - int? m_NotifyAfter; - - internal SqlServerInsertBulk(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, DataTable dataTable) : base(dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (dataTable == null) - throw new ArgumentNullException(nameof(dataTable), $"{nameof(dataTable)} is null."); - - m_DataSource = dataSource; - m_Source = dataTable.CreateDataReader(); - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - if (!m_Table.IsTable) - throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); - } + return new OperationExecutionToken(m_DataSource, "Bulk Insert into " + m_Table.Name); + } - internal SqlServerInsertBulk(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, IDataReader dataReader) : base(dataSource) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - if (dataReader == null) - throw new ArgumentNullException(nameof(dataReader), $"{nameof(dataReader)} is null."); - - m_DataSource = dataSource; - m_Source = dataReader; - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - if (!m_Table.IsTable) - throw new MappingException($"Cannot perform a bulk insert into the view {m_Table.Name}"); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// ExecutionToken<TCommand>. - public override OperationExecutionToken Prepare() - { - return new OperationExecutionToken(m_DataSource, "Bulk Insert into " + m_Table.Name); - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => m_Table.Columns.TryGetColumn(columnName); - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Modifies the batch size. - /// - /// Size of the batch. - /// SqlServerInsertBulk. - public SqlServerInsertBulk WithBatchSize(int batchSize) - { - m_BatchSize = batchSize; - return this; - } + /// + /// Modifies the batch size. + /// + /// Size of the batch. + /// SqlServerInsertBulk. + public SqlServerInsertBulk WithBatchSize(int batchSize) + { + m_BatchSize = batchSize; + return this; + } - /// - /// Modifies the batch size. - /// - /// Bulk insert options. - /// SqlServerInsertBulk. - public SqlServerInsertBulk WithOptions(SqlBulkCopyOptions options) - { - m_Options = options; - return this; - } + /// + /// After notifyAfter records, the event handler will be fired. This can be used to abort the bulk insert. + /// + /// The event handler. + /// The notify after. + public SqlServerInsertBulk WithNotifications(EventHandler eventHandler, int notifyAfter) + { + if (eventHandler == null) + throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); + if (notifyAfter <= 0) + throw new ArgumentException($"{nameof(notifyAfter)} must be greater than 0.", nameof(notifyAfter)); + m_EventHandler = eventHandler; + m_NotifyAfter = notifyAfter; + return this; + } - /// - /// After notifyAfter records, the event handler will be fired. This can be used to abort the bulk insert. - /// - /// The event handler. - /// The notify after. - public SqlServerInsertBulk WithNotifications(EventHandler eventHandler, int notifyAfter) - { - if (eventHandler == null) - throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); - if (notifyAfter <= 0) - throw new ArgumentException($"{nameof(notifyAfter)} must be greater than 0.", nameof(notifyAfter)); - m_EventHandler = eventHandler; - m_NotifyAfter = notifyAfter; - return this; - } + /// + /// Modifies the batch size. + /// + /// Bulk insert options. + /// SqlServerInsertBulk. + public SqlServerInsertBulk WithOptions(SqlBulkCopyOptions options) + { + m_Options = options; + return this; + } - /// - /// Enables streaming. - /// - /// SqlServerInsertBulk. - /// When EnableStreaming is true, SqlBulkCopy reads from an IDataReader object using SequentialAccess, optimizing memory usage by using the IDataReader streaming capabilities. When it’s set to false, the SqlBulkCopy class loads all the data returned by the IDataReader object into memory before sending it to SQL Server or SQL Azure. - public SqlServerInsertBulk WithStreaming() + /// + /// Enables streaming. + /// + /// SqlServerInsertBulk. + /// When EnableStreaming is true, SqlBulkCopy reads from an IDataReader object using SequentialAccess, optimizing memory usage by using the IDataReader streaming capabilities. When it’s set to false, the SqlBulkCopy class loads all the data returned by the IDataReader object into memory before sending it to SQL Server or SQL Azure. + public SqlServerInsertBulk WithStreaming() + { + m_EnableStreaming = true; + return this; + } + + /// + /// Implementation the specified operation. + /// + /// The connection. + /// The transaction. + /// System.Nullable<System.Int32>. + protected override int? Implementation(SqlConnection connection, SqlTransaction? transaction) + { + using (var bcp = new SqlBulkCopy(connection, m_Options, transaction)) { - m_EnableStreaming = true; - return this; + SetupBulkCopy(bcp); + + bcp.WriteToServer(m_Source); + return m_Source.RecordsAffected; } + } - /// - /// Implementation the specified operation. - /// - /// The connection. - /// The transaction. - /// System.Nullable<System.Int32>. - protected override int? Implementation(SqlConnection connection, SqlTransaction? transaction) + /// + /// Implementation the specified operation. + /// + /// The connection. + /// The transaction. + /// The cancellation token. + /// Task<System.Nullable<System.Int32>>. + protected override async Task ImplementationAsync(SqlConnection connection, SqlTransaction? transaction, CancellationToken cancellationToken) + { + using (var bcp = new SqlBulkCopy(connection, m_Options, transaction)) { - using (var bcp = new SqlBulkCopy(connection, m_Options, transaction)) - { - SetupBulkCopy(bcp); + SetupBulkCopy(bcp); - bcp.WriteToServer(m_Source); - return m_Source.RecordsAffected; - } + await bcp.WriteToServerAsync(m_Source).ConfigureAwait(false); + return m_Source.RecordsAffected; } + } - /// - /// Implementation the specified operation. - /// - /// The connection. - /// The transaction. - /// The cancellation token. - /// Task<System.Nullable<System.Int32>>. - protected override async Task ImplementationAsync(SqlConnection connection, SqlTransaction? transaction, CancellationToken cancellationToken) - { - using (var bcp = new SqlBulkCopy(connection, m_Options, transaction)) + void SetupBulkCopy(SqlBulkCopy bcp) + { + bcp.DestinationTableName = m_Table.Name.ToQuotedString(); + if (m_BatchSize.HasValue) + bcp.BatchSize = m_BatchSize.Value; + bcp.EnableStreaming = m_EnableStreaming; + + if (m_EventHandler != null) + bcp.SqlRowsCopied += (s, e) => { - SetupBulkCopy(bcp); + //Copy-in/copy-out is needed to get a generic event handler. + var e1 = new AbortableOperationEventArgs(e.RowsCopied); + m_EventHandler.Invoke(s, e1); + e.Abort = e1.Abort; + }; - await bcp.WriteToServerAsync(m_Source).ConfigureAwait(false); - return m_Source.RecordsAffected; - } - } + if (m_NotifyAfter.HasValue) + bcp.NotifyAfter = m_NotifyAfter.Value; - void SetupBulkCopy(SqlBulkCopy bcp) - { - bcp.DestinationTableName = m_Table.Name.ToQuotedString(); - if (m_BatchSize.HasValue) - bcp.BatchSize = m_BatchSize.Value; - bcp.EnableStreaming = m_EnableStreaming; - - if (m_EventHandler != null) - bcp.SqlRowsCopied += (s, e) => - { - //Copy-in/copy-out is needed to get a generic event handler. - var e1 = new AbortableOperationEventArgs(e.RowsCopied); - m_EventHandler.Invoke(s, e1); - e.Abort = e1.Abort; - }; - - if (m_NotifyAfter.HasValue) - bcp.NotifyAfter = m_NotifyAfter.Value; - - for (var i = 0; i < m_Source.FieldCount; i++) - bcp.ColumnMappings.Add(m_Source.GetName(i), m_Source.GetName(i)); - } + for (var i = 0; i < m_Source.FieldCount; i++) + bcp.ColumnMappings.Add(m_Source.GetName(i), m_Source.GetName(i)); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertObject.cs index af0eaa4a6..3a0fdcbd6 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertObject.cs @@ -2,70 +2,66 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerInsertObject. +/// +internal sealed class SqlServerInsertObject : SqlServerObjectCommand + where TArgument : class { + readonly InsertOptions m_Options; + /// - /// Class SqlServerInsertObject. + /// Initializes a new instance of the class. /// - internal sealed class SqlServerInsertObject : SqlServerObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public SqlServerInsertObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, InsertOptions options) + : base(dataSource, tableName, argumentValue) { - readonly InsertOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public SqlServerInsertObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, InsertOptions options) - : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; + var sql = new StringBuilder(); - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - sql.Append(header); + sqlBuilder.UseTableVariable(Table, out var header, out var intoClause, out var footer); + sql.Append(header); - bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} ON;"); + bool identityInsert = m_Options.HasFlag(InsertOptions.IdentityInsert); + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} ON;"); - sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToQuotedString()} (", null, ")", identityInsert); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); - sqlBuilder.BuildValuesClause(sql, " VALUES (", ")", identityInsert); - sql.Append(";"); + sqlBuilder.BuildInsertClause(sql, $"INSERT INTO {Table.Name.ToQuotedString()} (", null, ")", identityInsert); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); + sqlBuilder.BuildValuesClause(sql, " VALUES (", ")", identityInsert); + sql.Append(";"); - sql.Append(footer); + sql.Append(footer); - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} OFF;"); + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} OFF;"); - return new SqlServerCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); - } + return new SqlServerCommandExecutionToken(DataSource, "Insert into " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertOrUpdateObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertOrUpdateObject.cs index bd6c4a94a..20498ee30 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertOrUpdateObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerInsertOrUpdateObject.cs @@ -2,82 +2,78 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerInsertOrUpdateObject. +/// +internal sealed class SqlServerInsertOrUpdateObject : SqlServerObjectCommand + where TArgument : class { + readonly UpsertOptions m_Options; + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public SqlServerInsertOrUpdateObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpsertOptions options) : base(dataSource, tableName, argumentValue) + { + m_Options = options; + } + /// - /// Class SqlServerInsertOrUpdateObject. + /// Prepares the command for execution by generating any necessary SQL. /// - internal sealed class SqlServerInsertOrUpdateObject : SqlServerObjectCommand - where TArgument : class + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) { - readonly UpsertOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public SqlServerInsertOrUpdateObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpsertOptions options) : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } - - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); - - var availableColumns = sqlBuilder.GetParameterizedColumns().ToList(); - - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; - - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); - - sql.Append(header); - - var identityInsert = m_Options.HasFlag(UpsertOptions.IdentityInsert); - - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} ON;"); - - sql.Append($"MERGE INTO {Table.Name.ToQuotedString()} target USING "); sql.Append("(VALUES (" + string.Join(", ", availableColumns.Select(c => c.SqlVariableName)) + ")) AS source (" + string.Join(", ", availableColumns.Select(c => c.QuotedSqlName)) + ")"); - sql.Append(" ON "); - sql.Append(string.Join(" AND ", sqlBuilder.GetKeyColumns().ToList().Select(c => $"target.{c.QuotedSqlName} = source.{c.QuotedSqlName}"))); - - sql.Append(" WHEN MATCHED THEN UPDATE SET "); - sql.Append(string.Join(", ", sqlBuilder.GetUpdateColumns().Select(x => $"{x.QuotedSqlName} = source.{x.QuotedSqlName}"))); - - var insertColumns = sqlBuilder.GetInsertColumns(m_Options.HasFlag(UpsertOptions.IdentityInsert)); - sql.Append(" WHEN NOT MATCHED THEN INSERT ("); - sql.Append(string.Join(", ", insertColumns.Select(x => x.QuotedSqlName))); - sql.Append(") VALUES ("); - sql.Append(string.Join(", ", insertColumns.Select(x => "source." + x.QuotedSqlName))); - sql.Append(" )"); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); - sql.Append(";"); - sql.Append(footer); - - if (identityInsert) - sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} OFF;"); - - return new SqlServerCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); - } + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options); + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); + + var availableColumns = sqlBuilder.GetParameterizedColumns().ToList(); + + var sql = new StringBuilder(); + + sqlBuilder.UseTableVariable(Table, out var header, out var intoClause, out var footer); + + sql.Append(header); + + var identityInsert = m_Options.HasFlag(UpsertOptions.IdentityInsert); + + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} ON;"); + + sql.Append($"MERGE INTO {Table.Name.ToQuotedString()} target USING "); sql.Append("(VALUES (" + string.Join(", ", availableColumns.Select(c => c.SqlVariableName)) + ")) AS source (" + string.Join(", ", availableColumns.Select(c => c.QuotedSqlName)) + ")"); + sql.Append(" ON "); + sql.Append(string.Join(" AND ", sqlBuilder.GetKeyColumns().ToList().Select(c => $"target.{c.QuotedSqlName} = source.{c.QuotedSqlName}"))); + + sql.Append(" WHEN MATCHED THEN UPDATE SET "); + sql.Append(string.Join(", ", sqlBuilder.GetUpdateColumns().Select(x => $"{x.QuotedSqlName} = source.{x.QuotedSqlName}"))); + + var insertColumns = sqlBuilder.GetInsertColumns(m_Options.HasFlag(UpsertOptions.IdentityInsert)); + sql.Append(" WHEN NOT MATCHED THEN INSERT ("); + sql.Append(string.Join(", ", insertColumns.Select(x => x.QuotedSqlName))); + sql.Append(") VALUES ("); + sql.Append(string.Join(", ", insertColumns.Select(x => "source." + x.QuotedSqlName))); + sql.Append(" )"); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", "Inserted.", intoClause); + sql.Append(";"); + sql.Append(footer); + + if (identityInsert) + sql.AppendLine($"SET IDENTITY_INSERT {Table.Name.ToQuotedString()} OFF;"); + + return new SqlServerCommandExecutionToken(DataSource, "Insert or update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerObjectCommand.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerObjectCommand.cs index bdaa733e6..a853346f6 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerObjectCommand.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerObjectCommand.cs @@ -1,46 +1,45 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerObjectCommand. +/// +/// The type of the argument. +internal abstract class SqlServerObjectCommand : ObjectDbCommandBuilder + where TArgument : class { /// - /// Class SqlServerObjectCommand. + /// Initializes a new instance of the class. /// - /// The type of the argument. - internal abstract class SqlServerObjectCommand : ObjectDbCommandBuilder - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + protected SqlServerObjectCommand(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue) + : base(dataSource, argumentValue) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - protected SqlServerObjectCommand(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue) - : base(dataSource, argumentValue) - { - Table = DataSource.DatabaseMetadata.GetTableOrView(tableName); - } + Table = DataSource.DatabaseMetadata.GetTableOrView(tableName); + } - /// - /// Gets the data source. - /// - /// The data source. - public new SqlServerDataSourceBase DataSource - { - get { return (SqlServerDataSourceBase)base.DataSource; } - } + /// + /// Gets the data source. + /// + /// The data source. + public new SqlServerDataSourceBase DataSource + { + get { return (SqlServerDataSourceBase)base.DataSource; } + } - /// - /// Gets the table metadata. - /// - /// The metadata. - public SqlServerTableOrViewMetadata Table { get; } + /// + /// Gets the table metadata. + /// + /// The metadata. + public SqlServerTableOrViewMetadata Table { get; } - /// - /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. - /// - /// - protected override TableOrViewMetadata OnGetTable() => Table; - } -} + /// + /// Called when ObjectDbCommandBuilder needs a reference to the associated table or view. + /// + /// + protected override TableOrViewMetadata OnGetTable() => Table; +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerProcedureCall.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerProcedureCall.cs index ff64a74a2..e895c421b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerProcedureCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerProcedureCall.cs @@ -5,106 +5,104 @@ using Tortuga.Chain.Metadata; using Tortuga.Chain.SqlServer.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerProcedureCall. +/// +internal sealed partial class SqlServerProcedureCall : ProcedureDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly StoredProcedureMetadata m_Procedure; + /// - /// Class SqlServerProcedureCall. + /// Initializes a new instance of the class. /// - internal sealed partial class SqlServerProcedureCall : ProcedureDbCommandBuilder + /// The data source. + /// Name of the procedure. + /// The argument value. + internal SqlServerProcedureCall(SqlServerDataSourceBase dataSource, SqlServerObjectName procedureName, object? argumentValue = null) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly StoredProcedureMetadata m_Procedure; + if (procedureName == SqlServerObjectName.Empty) + throw new ArgumentException($"{nameof(procedureName)} is empty", nameof(procedureName)); - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the procedure. - /// The argument value. - internal SqlServerProcedureCall(SqlServerDataSourceBase dataSource, SqlServerObjectName procedureName, object? argumentValue = null) : base(dataSource) - { - if (procedureName == SqlServerObjectName.Empty) - throw new ArgumentException($"{nameof(procedureName)} is empty", nameof(procedureName)); - - m_ArgumentValue = argumentValue; - m_Procedure = DataSource.DatabaseMetadata.GetStoredProcedure(procedureName); - } + m_ArgumentValue = argumentValue; + m_Procedure = DataSource.DatabaseMetadata.GetStoredProcedure(procedureName); + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Gets the data source. + /// + /// The data source. + public new SqlServerDataSourceBase DataSource + { + get { return (SqlServerDataSourceBase)base.DataSource; } + } - List parameters; + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (m_ArgumentValue is IEnumerable) - { - parameters = ((IEnumerable)m_ArgumentValue).ToList(); - } - else - { - var sqlBuilder = m_Procedure.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyArgumentValue(DataSource, m_ArgumentValue); - parameters = sqlBuilder.GetParameters(); - } + List parameters; - return new SqlServerCommandExecutionToken(DataSource, m_Procedure.Name.ToString(), m_Procedure.Name.ToQuotedString(), parameters, CommandType.StoredProcedure); + if (m_ArgumentValue is IEnumerable) + { + parameters = ((IEnumerable)m_ArgumentValue).ToList(); } - - /// - /// Gets the data source. - /// - /// The data source. - public new SqlServerDataSourceBase DataSource + else { - get { return (SqlServerDataSourceBase)base.DataSource; } + var sqlBuilder = m_Procedure.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyArgumentValue(DataSource, m_ArgumentValue); + parameters = sqlBuilder.GetParameters(); } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => null; - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; + return new SqlServerCommandExecutionToken(DataSource, m_Procedure.Name.ToString(), m_Procedure.Name.ToQuotedString(), parameters, CommandType.StoredProcedure); } - partial class SqlServerProcedureCall : ISupportsChangeListener - { - /// - /// Waits for change in the data that is returned by this operation. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task that can be waited for. - /// This requires the use of SQL Dependency - public Task WaitForChange(CancellationToken cancellationToken, object? state = null) - { - return WaitForChangeMaterializer.GenerateTask(this, cancellationToken, state); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => null; - SqlServerCommandExecutionToken ISupportsChangeListener.Prepare(Materializer materializer) - { - return (SqlServerCommandExecutionToken)Prepare(materializer); - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; +} + +partial class SqlServerProcedureCall : ISupportsChangeListener +{ + SqlServerCommandExecutionToken ISupportsChangeListener.Prepare(Materializer materializer) + { + return (SqlServerCommandExecutionToken)Prepare(materializer); } + /// + /// Waits for change in the data that is returned by this operation. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task that can be waited for. + /// This requires the use of SQL Dependency + public Task WaitForChange(CancellationToken cancellationToken, object? state = null) + { + return WaitForChangeMaterializer.GenerateTask(this, cancellationToken, state); + } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerScalarFunction.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerScalarFunction.cs index d89006651..a13eaff42 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerScalarFunction.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerScalarFunction.cs @@ -6,84 +6,83 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Use for scalar functions. +/// +/// +internal class SqlServerScalarFunction : ScalarDbCommandBuilder { + readonly ScalarFunctionMetadata m_Function; + readonly object? m_FunctionArgumentValue; + /// - /// Use for scalar functions. + /// Initializes a new instance of the class. /// - /// - internal class SqlServerScalarFunction : ScalarDbCommandBuilder + /// The data source. + /// Name of the scalar function. + /// The function argument. + public SqlServerScalarFunction(SqlServerDataSourceBase dataSource, SqlServerObjectName scalarFunctionName, object? functionArgumentValue) : base(dataSource) { - readonly ScalarFunctionMetadata m_Function; - readonly object? m_FunctionArgumentValue; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the scalar function. - /// The function argument. - public SqlServerScalarFunction(SqlServerDataSourceBase dataSource, SqlServerObjectName scalarFunctionName, object? functionArgumentValue) : base(dataSource) - { - m_Function = dataSource.DatabaseMetadata.GetScalarFunction(scalarFunctionName); - m_FunctionArgumentValue = functionArgumentValue; - } + m_Function = dataSource.DatabaseMetadata.GetScalarFunction(scalarFunctionName); + m_FunctionArgumentValue = functionArgumentValue; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + /// + /// Gets the data source. + /// + /// The data source. + public new SqlServerDataSourceBase DataSource + { + get { return (SqlServerDataSourceBase)base.DataSource; } + } - var sqlBuilder = m_Function.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (m_FunctionArgumentValue != null) - sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); + var sqlBuilder = m_Function.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); - var sql = new StringBuilder(); - sqlBuilder.BuildFromFunctionClause(sql, $"SELECT {m_Function.Name.ToQuotedString()} (", " )"); - sql.Append(";"); + if (m_FunctionArgumentValue != null) + sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); - List parameters; - parameters = sqlBuilder.GetParameters(); + var sql = new StringBuilder(); + sqlBuilder.BuildFromFunctionClause(sql, $"SELECT {m_Function.Name.ToQuotedString()} (", " )"); + sql.Append(";"); - return new SqlServerCommandExecutionToken(DataSource, "Query Function " + m_Function.Name, sql.ToString(), parameters); - } + List parameters; + parameters = sqlBuilder.GetParameters(); - /// - /// Gets the data source. - /// - /// The data source. - public new SqlServerDataSourceBase DataSource - { - get { return (SqlServerDataSourceBase)base.DataSource; } - } + return new SqlServerCommandExecutionToken(DataSource, "Query Function " + m_Function.Name, sql.ToString(), parameters); + } - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// ColumnMetadata. - /// Always returns null since this command builder has no columns - public override ColumnMetadata? TryGetColumn(string columnName) => null; + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// ColumnMetadata. + /// Always returns null since this command builder has no columns + public override ColumnMetadata? TryGetColumn(string columnName) => null; - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerSqlCall.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerSqlCall.cs index 449e5c9a1..7cf79739b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerSqlCall.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerSqlCall.cs @@ -5,82 +5,80 @@ using Tortuga.Chain.Metadata; using Tortuga.Chain.SqlServer.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerSqlCall. +/// +internal sealed partial class SqlServerSqlCall : MultipleTableDbCommandBuilder { + readonly object? m_ArgumentValue; + readonly string m_SqlStatement; + /// - /// Class SqlServerSqlCall. + /// Initializes a new instance of the class. /// - internal sealed partial class SqlServerSqlCall : MultipleTableDbCommandBuilder + /// The data source. + /// The SQL statement. + /// The argument value. + /// sqlStatement is null or empty.;sqlStatement + public SqlServerSqlCall(SqlServerDataSourceBase dataSource, string sqlStatement, object? argumentValue) : base(dataSource) { - readonly object? m_ArgumentValue; - readonly string m_SqlStatement; + if (string.IsNullOrEmpty(sqlStatement)) + throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// The SQL statement. - /// The argument value. - /// sqlStatement is null or empty.;sqlStatement - public SqlServerSqlCall(SqlServerDataSourceBase dataSource, string sqlStatement, object? argumentValue) : base(dataSource) - { - if (string.IsNullOrEmpty(sqlStatement)) - throw new ArgumentException($"{nameof(sqlStatement)} is null or empty.", nameof(sqlStatement)); + m_SqlStatement = sqlStatement; + m_ArgumentValue = argumentValue; + } - m_SqlStatement = sqlStatement; - m_ArgumentValue = argumentValue; - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + return new SqlServerCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - return new SqlServerCommandExecutionToken(DataSource, "Raw SQL call", m_SqlStatement, SqlBuilder.GetParameters(m_ArgumentValue)); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) => null; - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) => null; + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; +} - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => ImmutableList.Empty; +partial class SqlServerSqlCall : ISupportsChangeListener +{ + SqlServerCommandExecutionToken ISupportsChangeListener.Prepare(Materializer materializer) + { + return (SqlServerCommandExecutionToken)Prepare(materializer); } - partial class SqlServerSqlCall : ISupportsChangeListener + /// + /// Waits for change in the data that is returned by this operation. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task that can be waited for. + /// This requires the use of SQL Dependency + public Task WaitForChange(CancellationToken cancellationToken, object? state = null) { - SqlServerCommandExecutionToken ISupportsChangeListener.Prepare(Materializer materializer) - { - return (SqlServerCommandExecutionToken)Prepare(materializer); - } - - /// - /// Waits for change in the data that is returned by this operation. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task that can be waited for. - /// This requires the use of SQL Dependency - public Task WaitForChange(CancellationToken cancellationToken, object? state = null) - { - return WaitForChangeMaterializer.GenerateTask(this, cancellationToken, state); - } + return WaitForChangeMaterializer.GenerateTask(this, cancellationToken, state); } - } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableFunction.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableFunction.cs index d6c175beb..6f1565864 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableFunction.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableFunction.cs @@ -4,333 +4,336 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Use for table-valued functions. +/// +/// +internal class SqlServerTableFunction : TableDbCommandBuilder, ISupportsApproximateCount { + readonly object? m_FunctionArgumentValue; + readonly TableFunctionMetadata m_Table; + object? m_ArgumentValue; + FilterOptions m_FilterOptions; + object? m_FilterValue; + SqlServerLimitOption m_LimitOptions; + int? m_Seed; + string? m_SelectClause; + int? m_Skip; + IEnumerable m_SortExpressions = Enumerable.Empty(); + int? m_Take; + string? m_WhereClause; + /// - /// Use for table-valued functions. + /// Initializes a new instance of the class. /// - /// - internal class SqlServerTableFunction : TableDbCommandBuilder, ISupportsApproximateCount + /// The data source. + /// Name of the table function. + /// The function argument. + public SqlServerTableFunction(SqlServerDataSourceBase dataSource, SqlServerObjectName tableFunctionName, object? functionArgumentValue) : base(dataSource) { - readonly TableFunctionMetadata m_Table; - readonly object? m_FunctionArgumentValue; - object? m_FilterValue; - string? m_WhereClause; - object? m_ArgumentValue; - IEnumerable m_SortExpressions = Enumerable.Empty(); - SqlServerLimitOption m_LimitOptions; - int? m_Skip; - int? m_Take; - int? m_Seed; - string? m_SelectClause; - FilterOptions m_FilterOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table function. - /// The function argument. - public SqlServerTableFunction(SqlServerDataSourceBase dataSource, SqlServerObjectName tableFunctionName, object? functionArgumentValue) : base(dataSource) - { - m_Table = dataSource.DatabaseMetadata.GetTableFunction(tableFunctionName); - m_FunctionArgumentValue = functionArgumentValue; - } + m_Table = dataSource.DatabaseMetadata.GetTableFunction(tableFunctionName); + m_FunctionArgumentValue = functionArgumentValue; + } - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + /// + /// Gets the data source. + /// + /// The data source. + public new SqlServerDataSourceBase DataSource + { + get { return (SqlServerDataSourceBase)base.DataSource; } + } - m_SortExpressions = sortExpressions; - return this; - } + /// + /// Returns the row count using a SELECT Count(*) style query. + /// + /// + public override ILink AsCount() + { + m_SelectClause = "COUNT_BIG(*)"; + return ToInt64(); + } + + /// + /// Returns the row count for a given column. SELECT Count(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT(DISTINCT columnName). + /// + public override ILink AsCount(string columnName, bool distinct = false) + { + var column = m_Table.Columns[columnName]; + if (distinct) + m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; + else + m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; + + return ToInt64(); + } + + /// + /// Return the approximate distinct count using the APPROX_COUNT_DISTINCT function. + /// + /// Name of the column. + public ILink AsCountApproximate(string columnName) + { + var column = m_Table.Columns[columnName]; + m_SelectClause = $"APPROX_COUNT_DISTINCT({column.QuotedSqlName})"; + + return ToInt64(); + } + + /// + /// Return the approximate row count using the APPROX_COUNT_DISTINCT function. + /// + /// This is only available on tables with a single primary key. + public ILink AsCountApproximate() + { + throw new NotSupportedException($"{nameof(AsCountApproximate)}() operation isn't allowed on {m_Table.Name} because it doesn't have a single primary key. Please provide a column name."); + } + + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// + /// ExecutionToken<TCommand>. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); + + if (m_FunctionArgumentValue != null) + sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); + if (m_SelectClause == null) { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = limitOptions; - return this; + var desired = materializer.DesiredColumns(); + if (desired == Materializer.AutoSelectDesiredColumns) + desired = Materializer.AllColumns; + sqlBuilder.ApplyDesiredColumns(desired); } - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + //Support check + if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) + throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); + if (m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) + throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions} with table-valued functions"); + if (m_Seed.HasValue) + throw new NotSupportedException($"SQL Server does not setting a random seed for table-valued functions"); + + //Validation + if (m_Skip < 0) + throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); + + if (m_Skip > 0 && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); + + if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) + throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); + + if (m_Take <= 0) + throw new InvalidOperationException($"Cannot take {m_Take} rows"); + + if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); + + //SQL Generation + List parameters; + var sql = new StringBuilder(); + + string? topClause = null; + switch (m_LimitOptions) { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = (SqlServerLimitOption)limitOptions; - return this; + case SqlServerLimitOption.Rows: + if (!m_SortExpressions.Any()) + topClause = $"TOP (@fetch_row_count_expression) "; + break; + + case SqlServerLimitOption.Percentage: + topClause = $"TOP (@fetch_row_count_expression) PERCENT "; + break; + + case SqlServerLimitOption.PercentageWithTies: + topClause = $"TOP (@fetch_row_count_expression) PERCENT WITH TIES "; + break; + + case SqlServerLimitOption.RowsWithTies: + topClause = $"TOP (@fetch_row_count_expression) WITH TIES "; + break; } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<SqlCommand, SqlParameter, SqlServerLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + if (m_SelectClause != null) + sql.Append($"SELECT {topClause} {m_SelectClause} "); + else + sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); + + sqlBuilder.BuildFromFunctionClause(sql, $" FROM {m_Table.Name.ToQuotedString()} (", " ) "); + + if (m_FilterValue != null) { - m_FilterValue = filterValue; - m_WhereClause = null; - m_ArgumentValue = null; - m_FilterOptions = filterOptions; - return this; + sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); + + parameters = sqlBuilder.GetParameters(); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE (" + m_WhereClause + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - m_FilterValue = null; - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - return this; + sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); + parameters = sqlBuilder.GetParameters(); } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// - /// ExecutionToken<TCommand>. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any() && StrictMode) + throw new InvalidOperationException("Limits were requested without a sort order. Use WithSorting to supply a sort order or disable strict mode."); + + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + + switch (m_LimitOptions) { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); - - if (m_FunctionArgumentValue != null) - sqlBuilder.ApplyArgumentValue(DataSource, m_FunctionArgumentValue); - if (m_SelectClause == null) - { - var desired = materializer.DesiredColumns(); - if (desired == Materializer.AutoSelectDesiredColumns) - desired = Materializer.AllColumns; - sqlBuilder.ApplyDesiredColumns(desired); - } - - //Support check - if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) - throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); - if (m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) - throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions} with table-valued functions"); - if (m_Seed.HasValue) - throw new NotSupportedException($"SQL Server does not setting a random seed for table-valued functions"); - - //Validation - if (m_Skip < 0) - throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); - - if (m_Skip > 0 && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); - - if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) - throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); - - if (m_Take <= 0) - throw new InvalidOperationException($"Cannot take {m_Take} rows"); - - if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); - - //SQL Generation - List parameters; - var sql = new StringBuilder(); - - string? topClause = null; - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - if (!m_SortExpressions.Any()) - topClause = $"TOP (@fetch_row_count_expression) "; - break; - - case SqlServerLimitOption.Percentage: - topClause = $"TOP (@fetch_row_count_expression) PERCENT "; - break; - - case SqlServerLimitOption.PercentageWithTies: - topClause = $"TOP (@fetch_row_count_expression) PERCENT WITH TIES "; - break; - - case SqlServerLimitOption.RowsWithTies: - topClause = $"TOP (@fetch_row_count_expression) WITH TIES "; - break; - } - - if (m_SelectClause != null) - sql.Append($"SELECT {topClause} {m_SelectClause} "); - else - sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); - - sqlBuilder.BuildFromFunctionClause(sql, $" FROM {m_Table.Name.ToQuotedString()} (", " ) "); - - if (m_FilterValue != null) - { - sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE (" + m_WhereClause + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); - parameters = sqlBuilder.GetParameters(); - } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); - - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - if (m_SortExpressions.Any()) - { - sql.Append(" OFFSET @offset_row_count_expression ROWS "); - parameters.Add(new SqlParameter("@offset_row_count_expression", m_Skip ?? 0)); - - if (m_Take.HasValue) - { - sql.Append(" FETCH NEXT @fetch_row_count_expression ROWS ONLY"); - parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); - } - } - else + case SqlServerLimitOption.Rows: + if (m_SortExpressions.Any()) + { + sql.Append(" OFFSET @offset_row_count_expression ROWS "); + parameters.Add(new SqlParameter("@offset_row_count_expression", m_Skip ?? 0)); + + if (m_Take.HasValue) { + sql.Append(" FETCH NEXT @fetch_row_count_expression ROWS ONLY"); parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); } - break; - - case SqlServerLimitOption.Percentage: - case SqlServerLimitOption.PercentageWithTies: - case SqlServerLimitOption.RowsWithTies: + } + else + { parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); + } + break; - break; - } - - sql.Append(";"); + case SqlServerLimitOption.Percentage: + case SqlServerLimitOption.PercentageWithTies: + case SqlServerLimitOption.RowsWithTies: + parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); - return new SqlServerCommandExecutionToken(DataSource, "Query Function " + m_Table.Name, sql.ToString(), parameters); + break; } - /// - /// Returns the row count using a SELECT Count(*) style query. - /// - /// - public override ILink AsCount() - { - m_SelectClause = "COUNT_BIG(*)"; - return ToInt64(); - } + sql.Append(";"); - /// - /// Returns the row count for a given column. SELECT Count(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT(DISTINCT columnName). - /// - public override ILink AsCount(string columnName, bool distinct = false) - { - var column = m_Table.Columns[columnName]; - if (distinct) - m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; - else - m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; + return new SqlServerCommandExecutionToken(DataSource, "Query Function " + m_Table.Name, sql.ToString(), parameters); + } - return ToInt64(); - } + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } - /// - /// Gets the data source. - /// - /// The data source. - public new SqlServerDataSourceBase DataSource - { - get { return (SqlServerDataSourceBase)base.DataSource; } - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NullableColumns; - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) - { - return m_Table.Columns.TryGetColumn(columnName); - } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// TableDbCommandBuilder<SqlCommand, SqlParameter, SqlServerLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_FilterValue = filterValue; + m_WhereClause = null; + m_ArgumentValue = null; + m_FilterOptions = filterOptions; + return this; + } - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NullableColumns; - - /// - /// Return the approximate distinct count using the APPROX_COUNT_DISTINCT function. - /// - /// Name of the column. - public ILink AsCountApproximate(string columnName) - { - var column = m_Table.Columns[columnName]; - m_SelectClause = $"APPROX_COUNT_DISTINCT({column.QuotedSqlName})"; + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + { + m_FilterValue = null; + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + return this; + } - return ToInt64(); - } + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = limitOptions; + return this; + } - /// - /// Return the approximate row count using the APPROX_COUNT_DISTINCT function. - /// - /// This is only available on tables with a single primary key. - public ILink AsCountApproximate() - { - throw new NotSupportedException($"{nameof(AsCountApproximate)}() operation isn't allowed on {m_Table.Name} because it doesn't have a single primary key. Please provide a column name."); - } + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = (SqlServerLimitOption)limitOptions; + return this; + } + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableOrView.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableOrView.cs index de849b9d9..9e5ef9f31 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableOrView.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerTableOrView.cs @@ -5,386 +5,395 @@ using Tortuga.Chain.Metadata; using Tortuga.Chain.SqlServer.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// SqlServerTableOrView supports queries against tables and views. +/// +internal sealed partial class SqlServerTableOrView : TableDbCommandBuilder, ISupportsApproximateCount + where TObject : class { + readonly TableOrViewMetadata m_Table; + object? m_ArgumentValue; + FilterOptions m_FilterOptions; + object? m_FilterValue; + SqlServerLimitOption m_LimitOptions; + int? m_Seed; + string? m_SelectClause; + int? m_Skip; + IEnumerable m_SortExpressions = Enumerable.Empty(); + int? m_Take; + string? m_WhereClause; + /// - /// SqlServerTableOrView supports queries against tables and views. + /// Initializes a new instance of the class. /// - internal sealed partial class SqlServerTableOrView : TableDbCommandBuilder, ISupportsApproximateCount - where TObject : class + /// The data source. + /// Name of the table or view. + /// The filter value. + /// The filter options. + /// + public SqlServerTableOrView(SqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None) : base(dataSource) { - readonly TableOrViewMetadata m_Table; - object? m_FilterValue; - string? m_WhereClause; - object? m_ArgumentValue; - IEnumerable m_SortExpressions = Enumerable.Empty(); - SqlServerLimitOption m_LimitOptions; - int? m_Skip; - int? m_Take; - int? m_Seed; - string? m_SelectClause; - FilterOptions m_FilterOptions; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The filter value. - /// The filter options. - /// - public SqlServerTableOrView(SqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, object filterValue, FilterOptions filterOptions = FilterOptions.None) : base(dataSource) - { - if (tableOrViewName == SqlServerObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + if (tableOrViewName == SqlServerObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - } + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table or view. - /// The where clause. - /// The argument value. - public SqlServerTableOrView(SqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, string? whereClause, object? argumentValue) : base(dataSource) - { - if (tableOrViewName == SqlServerObjectName.Empty) - throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table or view. + /// The where clause. + /// The argument value. + public SqlServerTableOrView(SqlServerDataSourceBase dataSource, SqlServerObjectName tableOrViewName, string? whereClause, object? argumentValue) : base(dataSource) + { + if (tableOrViewName == SqlServerObjectName.Empty) + throw new ArgumentException($"{nameof(tableOrViewName)} is empty", nameof(tableOrViewName)); - m_ArgumentValue = argumentValue; - m_WhereClause = whereClause; - m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); - } + m_ArgumentValue = argumentValue; + m_WhereClause = whereClause; + m_Table = DataSource.DatabaseMetadata.GetTableOrView(tableOrViewName); + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - sqlBuilder.ApplyRulesForSelect(DataSource); - - if (m_SelectClause == null) - sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); - - //Support check - if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) - throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); - - //Validation - if (m_Skip < 0) - throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); - - if (m_Skip > 0 && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); - - if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) - throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); - - if (m_Take <= 0) - throw new InvalidOperationException($"Cannot take {m_Take} rows"); - - if ((m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) && m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform random sampling when sorting."); - - if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) - throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); - - //SQL Generation - List parameters; - var sql = new StringBuilder(); - - string? topClause = null; - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: - if (!m_SortExpressions.Any()) - topClause = $"TOP (@fetch_row_count_expression) "; - break; - - case SqlServerLimitOption.Percentage: - topClause = $"TOP (@fetch_row_count_expression) PERCENT "; - break; - - case SqlServerLimitOption.PercentageWithTies: - topClause = $"TOP (@fetch_row_count_expression) PERCENT WITH TIES "; - break; - - case SqlServerLimitOption.RowsWithTies: - topClause = $"TOP (@fetch_row_count_expression) WITH TIES "; - break; - } - - if (m_SelectClause != null) - sql.Append($"SELECT {topClause} {m_SelectClause} "); - else - sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); - - sql.Append(" FROM " + m_Table.Name.ToQuotedString()); - - switch (m_LimitOptions) - { - case SqlServerLimitOption.TableSampleSystemRows: - sql.Append($" TABLESAMPLE SYSTEM ({m_Take} ROWS) "); - if (m_Seed.HasValue) - sql.Append($"REPEATABLE ({m_Seed}) "); - break; - - case SqlServerLimitOption.TableSampleSystemPercentage: - sql.Append($" TABLESAMPLE SYSTEM ({m_Take} PERCENT) "); - if (m_Seed.HasValue) - sql.Append($"REPEATABLE ({m_Seed}) "); - break; - } - - if (m_FilterValue != null) - { - sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = sqlBuilder.GetParameters(); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE (" + m_WhereClause + ")"); - sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - - parameters = SqlBuilder.GetParameters(m_ArgumentValue); - parameters.AddRange(sqlBuilder.GetParameters()); - } - else - { - sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); - parameters = sqlBuilder.GetParameters(); - } - sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); + /// + /// Gets the data source. + /// + /// The data source. + public new SqlServerDataSourceBase DataSource + { + get { return (SqlServerDataSourceBase)base.DataSource; } + } - switch (m_LimitOptions) - { - case SqlServerLimitOption.Rows: + /// + /// Returns the row count using a SELECT COUNT_BIG(*) style query. + /// + /// + public override ILink AsCount() + { + m_SelectClause = "COUNT_BIG(*)"; + return ToInt64(); + } - if (m_SortExpressions.Any()) - { - sql.Append(" OFFSET @offset_row_count_expression ROWS "); - parameters.Add(new SqlParameter("@offset_row_count_expression", m_Skip ?? 0)); - - if (m_Take.HasValue) - { - sql.Append(" FETCH NEXT @fetch_row_count_expression ROWS ONLY"); - parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); - } - } - else - { - parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); - } - break; + /// + /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) + /// + /// Name of the column. + /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). + /// + public override ILink AsCount(string columnName, bool distinct = false) + { + var column = m_Table.Columns[columnName]; + if (distinct) + m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; + else + m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; - case SqlServerLimitOption.Percentage: - case SqlServerLimitOption.PercentageWithTies: - case SqlServerLimitOption.RowsWithTies: - parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); + return ToInt64(); + } - break; - } + /// + /// Return the approximate distinct count using the APPROX_COUNT_DISTINCT function. + /// + /// Name of the column. + public ILink AsCountApproximate(string columnName) + { + var column = m_Table.Columns[columnName]; + m_SelectClause = $"APPROX_COUNT_DISTINCT({column.QuotedSqlName})"; - sql.Append(";"); + return ToInt64(); + } - return new SqlServerCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); - } + /// + /// Return the approximate row count using the APPROX_COUNT_DISTINCT function. + /// + /// This is only available on tables with a single primary key. + public ILink AsCountApproximate() + { + var primaryKeys = m_Table.PrimaryKeyColumns; + if (primaryKeys.Count != 1) + throw new MappingException($"{nameof(AsCountApproximate)}() operation isn't allowed on {m_Table.Name} because it doesn't have a single primary key. Please provide a column name."); - /// - /// Adds sorting to the command builder. - /// - /// The sort expressions. - /// - protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) - { - if (sortExpressions == null) - throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + m_SelectClause = $"APPROX_COUNT_DISTINCT({primaryKeys.Single().QuotedSqlName})"; - m_SortExpressions = sortExpressions; - return this; - } + return ToInt64(); + } - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) - { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = limitOptions; - return this; - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - /// - /// Adds limits to the command builder. - /// - /// The number of rows to skip. - /// Number of rows to take. - /// The limit options. - /// The seed for repeatable reads. Only applies to random sampling - /// - protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) - { - m_Seed = seed; - m_Skip = skip; - m_Take = take; - m_LimitOptions = (SqlServerLimitOption)limitOptions; - return this; - } + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + sqlBuilder.ApplyRulesForSelect(DataSource); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - /// TableDbCommandBuilder<SqlCommand, SqlParameter, SqlServerLimitOption>. - protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) - { - m_FilterValue = filterValue; - m_WhereClause = null; - m_ArgumentValue = null; - m_FilterOptions = filterOptions; - return this; - } + if (m_SelectClause == null) + sqlBuilder.ApplyDesiredColumns(materializer.DesiredColumns()); + + //Support check + if (!Enum.IsDefined(typeof(SqlServerLimitOption), m_LimitOptions)) + throw new NotSupportedException($"SQL Server does not support limit option {(LimitOptions)m_LimitOptions}"); + + //Validation + if (m_Skip < 0) + throw new InvalidOperationException($"Cannot skip {m_Skip} rows"); + + if (m_Skip > 0 && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a Skip operation with out a sort expression."); + + if (m_Skip > 0 && m_LimitOptions != SqlServerLimitOption.Rows) + throw new InvalidOperationException($"Cannot perform a Skip operation with limit option {m_LimitOptions}"); + + if (m_Take <= 0) + throw new InvalidOperationException($"Cannot take {m_Take} rows"); + + if ((m_LimitOptions == SqlServerLimitOption.TableSampleSystemRows || m_LimitOptions == SqlServerLimitOption.TableSampleSystemPercentage) && m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform random sampling when sorting."); + + if ((m_LimitOptions == SqlServerLimitOption.RowsWithTies || m_LimitOptions == SqlServerLimitOption.PercentageWithTies) && !m_SortExpressions.Any()) + throw new InvalidOperationException($"Cannot perform a WITH TIES operation without sorting."); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + //SQL Generation + List parameters; + var sql = new StringBuilder(); + + string? topClause = null; + switch (m_LimitOptions) { - m_FilterValue = null; - m_WhereClause = whereClause; - m_ArgumentValue = argumentValue; - return this; + case SqlServerLimitOption.Rows: + if (!m_SortExpressions.Any()) + topClause = $"TOP (@fetch_row_count_expression) "; + break; + + case SqlServerLimitOption.Percentage: + topClause = $"TOP (@fetch_row_count_expression) PERCENT "; + break; + + case SqlServerLimitOption.PercentageWithTies: + topClause = $"TOP (@fetch_row_count_expression) PERCENT WITH TIES "; + break; + + case SqlServerLimitOption.RowsWithTies: + topClause = $"TOP (@fetch_row_count_expression) WITH TIES "; + break; } - /// - /// Returns the row count using a SELECT COUNT_BIG(*) style query. - /// - /// - public override ILink AsCount() + if (m_SelectClause != null) + sql.Append($"SELECT {topClause} {m_SelectClause} "); + else + sqlBuilder.BuildSelectClause(sql, "SELECT " + topClause, null, null); + + sql.Append(" FROM " + m_Table.Name.ToQuotedString()); + + switch (m_LimitOptions) { - m_SelectClause = "COUNT_BIG(*)"; - return ToInt64(); + case SqlServerLimitOption.TableSampleSystemRows: + sql.Append($" TABLESAMPLE SYSTEM ({m_Take} ROWS) "); + if (m_Seed.HasValue) + sql.Append($"REPEATABLE ({m_Seed}) "); + break; + + case SqlServerLimitOption.TableSampleSystemPercentage: + sql.Append($" TABLESAMPLE SYSTEM ({m_Take} PERCENT) "); + if (m_Seed.HasValue) + sql.Append($"REPEATABLE ({m_Seed}) "); + break; } - /// - /// Returns the row count for a given column. SELECT COUNT_BIG(columnName) - /// - /// Name of the column. - /// if set to true use SELECT COUNT_BIG(DISTINCT columnName). - /// - public override ILink AsCount(string columnName, bool distinct = false) + if (m_FilterValue != null) { - var column = m_Table.Columns[columnName]; - if (distinct) - m_SelectClause = $"COUNT_BIG(DISTINCT {column.QuotedSqlName})"; - else - m_SelectClause = $"COUNT_BIG({column.QuotedSqlName})"; + sql.Append(" WHERE (" + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions) + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - return ToInt64(); + parameters = sqlBuilder.GetParameters(); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE (" + m_WhereClause + ")"); + sqlBuilder.BuildSoftDeleteClause(sql, " AND (", DataSource, ") "); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + parameters = SqlBuilder.GetParameters(m_ArgumentValue); + parameters.AddRange(sqlBuilder.GetParameters()); + } + else { - return m_Table.Columns.TryGetColumn(columnName); + sqlBuilder.BuildSoftDeleteClause(sql, " WHERE ", DataSource, null); + parameters = sqlBuilder.GetParameters(); } - /// - /// Gets the data source. - /// - /// The data source. - public new SqlServerDataSourceBase DataSource + if (m_LimitOptions.RequiresSorting() && !m_SortExpressions.Any()) { - get { return (SqlServerDataSourceBase)base.DataSource; } + if (m_Table.HasPrimaryKey) + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_Table.PrimaryKeyColumns.Select(x => new SortExpression(x.SqlName)), null); + else if (StrictMode) + throw new InvalidOperationException("Limits were requested, but no primary keys were detected. Use WithSorting to supply a sort order or disable strict mode."); } - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Return the approximate distinct count using the APPROX_COUNT_DISTINCT function. - /// - /// Name of the column. - public ILink AsCountApproximate(string columnName) + else { - var column = m_Table.Columns[columnName]; - m_SelectClause = $"APPROX_COUNT_DISTINCT({column.QuotedSqlName})"; - - return ToInt64(); + sqlBuilder.BuildOrderByClause(sql, " ORDER BY ", m_SortExpressions, null); } - /// - /// Return the approximate row count using the APPROX_COUNT_DISTINCT function. - /// - /// This is only available on tables with a single primary key. - public ILink AsCountApproximate() + switch (m_LimitOptions) { - var primaryKeys = m_Table.PrimaryKeyColumns; - if (primaryKeys.Count != 1) - throw new MappingException($"{nameof(AsCountApproximate)}() operation isn't allowed on {m_Table.Name} because it doesn't have a single primary key. Please provide a column name."); + case SqlServerLimitOption.Rows: - m_SelectClause = $"APPROX_COUNT_DISTINCT({primaryKeys.Single().QuotedSqlName})"; + if (m_SortExpressions.Any()) + { + sql.Append(" OFFSET @offset_row_count_expression ROWS "); + parameters.Add(new SqlParameter("@offset_row_count_expression", m_Skip ?? 0)); - return ToInt64(); + if (m_Take.HasValue) + { + sql.Append(" FETCH NEXT @fetch_row_count_expression ROWS ONLY"); + parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); + } + } + else + { + parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); + } + break; + + case SqlServerLimitOption.Percentage: + case SqlServerLimitOption.PercentageWithTies: + case SqlServerLimitOption.RowsWithTies: + parameters.Add(new SqlParameter("@fetch_row_count_expression", m_Take)); + + break; } + + sql.Append(";"); + + return new SqlServerCommandExecutionToken(DataSource, "Query " + m_Table.Name, sql.ToString(), parameters); } - partial class SqlServerTableOrView : ISupportsChangeListener + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) { - /// - /// Waits for change in the data that is returned by this operation. - /// - /// The cancellation token. - /// User defined state, usually used for logging. - /// Task that can be waited for. - /// This requires the use of SQL Dependency - public Task WaitForChange(CancellationToken cancellationToken, object? state = null) - { - return WaitForChangeMaterializer.GenerateTask(this, cancellationToken, state); - } + return m_Table.Columns.TryGetColumn(columnName); + } - SqlServerCommandExecutionToken ISupportsChangeListener.Prepare(Materializer materializer) - { - return (SqlServerCommandExecutionToken)Prepare(materializer); - } + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + /// TableDbCommandBuilder<SqlCommand, SqlParameter, SqlServerLimitOption>. + protected override TableDbCommandBuilder OnWithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_FilterValue = filterValue; + m_WhereClause = null; + m_ArgumentValue = null; + m_FilterOptions = filterOptions; + return this; } + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + protected override TableDbCommandBuilder OnWithFilter(string whereClause, object? argumentValue) + { + m_FilterValue = null; + m_WhereClause = whereClause; + m_ArgumentValue = argumentValue; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, SqlServerLimitOption limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = limitOptions; + return this; + } + + /// + /// Adds limits to the command builder. + /// + /// The number of rows to skip. + /// Number of rows to take. + /// The limit options. + /// The seed for repeatable reads. Only applies to random sampling + /// + protected override TableDbCommandBuilder OnWithLimits(int? skip, int? take, LimitOptions limitOptions, int? seed) + { + m_Seed = seed; + m_Skip = skip; + m_Take = take; + m_LimitOptions = (SqlServerLimitOption)limitOptions; + return this; + } + + /// + /// Adds sorting to the command builder. + /// + /// The sort expressions. + /// + protected override TableDbCommandBuilder OnWithSorting(IEnumerable sortExpressions) + { + if (sortExpressions == null) + throw new ArgumentNullException(nameof(sortExpressions), $"{nameof(sortExpressions)} is null."); + + m_SortExpressions = sortExpressions; + return this; + } } + +partial class SqlServerTableOrView : ISupportsChangeListener +{ + SqlServerCommandExecutionToken ISupportsChangeListener.Prepare(Materializer materializer) + { + return (SqlServerCommandExecutionToken)Prepare(materializer); + } + + /// + /// Waits for change in the data that is returned by this operation. + /// + /// The cancellation token. + /// User defined state, usually used for logging. + /// Task that can be waited for. + /// This requires the use of SQL Dependency + public Task WaitForChange(CancellationToken cancellationToken, object? state = null) + { + return WaitForChangeMaterializer.GenerateTask(this, cancellationToken, state); + } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateObject.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateObject.cs index f1a759e21..00a5dc018 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateObject.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateObject.cs @@ -3,71 +3,67 @@ using Tortuga.Chain.Core; using Tortuga.Chain.Materializers; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerUpdateObject. +/// +internal sealed class SqlServerUpdateObject : SqlServerObjectCommand + where TArgument : class { + readonly UpdateOptions m_Options; + /// - /// Class SqlServerUpdateObject. + /// Initializes a new instance of the class. /// - internal sealed class SqlServerUpdateObject : SqlServerObjectCommand - where TArgument : class + /// The data source. + /// Name of the table. + /// The argument value. + /// The options. + public SqlServerUpdateObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpdateOptions options) : base(dataSource, tableName, argumentValue) { - readonly UpdateOptions m_Options; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The argument value. - /// The options. - public SqlServerUpdateObject(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, TArgument argumentValue, UpdateOptions options) : base(dataSource, tableName, argumentValue) - { - m_Options = options; - } + m_Options = options; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UpdateOptions")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UseKeyAttribute")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "WithKeys")] - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UpdateOptions")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UseKeyAttribute")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "WithKeys")] + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) - throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); + if (!Table.HasPrimaryKey && !m_Options.HasFlag(UpdateOptions.UseKeyAttribute) && KeyColumns.Count == 0) + throw new MappingException($"Cannot perform an update operation on {Table.Name} unless UpdateOptions.UseKeyAttribute or .WithKeys() is specified."); - var sqlBuilder = Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); + var sqlBuilder = Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, ArgumentValue, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); - if (KeyColumns.Count > 0) - sqlBuilder.OverrideKeys(KeyColumns); + if (KeyColumns.Count > 0) + sqlBuilder.OverrideKeys(KeyColumns); - var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; + var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; + var sql = new StringBuilder(); - sqlBuilder.UseTableVariable(Table, out header, out intoClause, out footer); + sqlBuilder.UseTableVariable(Table, out var header, out var intoClause, out var footer); - sql.Append(header); - sql.Append($"UPDATE {Table.Name.ToQuotedString()}"); - sqlBuilder.BuildSetClause(sql, " SET ", null, null); - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); - sqlBuilder.BuildWhereClause(sql, " WHERE ", null); - sql.Append(";"); - sql.Append(footer); + sql.Append(header); + sql.Append($"UPDATE {Table.Name.ToQuotedString()}"); + sqlBuilder.BuildSetClause(sql, " SET ", null, null); + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); + sqlBuilder.BuildWhereClause(sql, " WHERE ", null); + sql.Append(";"); + sql.Append(footer); - return new SqlServerCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckUpdateRowCount(m_Options); - } + return new SqlServerCommandExecutionToken(DataSource, "Update " + Table.Name, sql.ToString(), sqlBuilder.GetParameters()).CheckUpdateRowCount(m_Options); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateSet.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateSet.cs index 76fa11bce..8db0594de 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateSet.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/CommandBuilders/SqlServerUpdateSet.cs @@ -4,235 +4,231 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer.CommandBuilders +namespace Tortuga.Chain.SqlServer.CommandBuilders; + +/// +/// Class SqlServerUpdateSet. +/// +internal sealed class SqlServerUpdateSet : UpdateSetDbCommandBuilder { + readonly int? m_ExpectedRowCount; + readonly object? m_NewValues; + readonly UpdateOptions m_Options; + readonly IEnumerable? m_Parameters; + readonly SqlServerTableOrViewMetadata m_Table; + readonly object? m_UpdateArgumentValue; + readonly string? m_UpdateExpression; + FilterOptions m_FilterOptions; + object? m_FilterValue; + object? m_WhereArgumentValue; + string? m_WhereClause; + /// - /// Class SqlServerUpdateSet. + /// Initializes a new instance of the class. /// - internal sealed class SqlServerUpdateSet : UpdateSetDbCommandBuilder + /// The data source. + /// Name of the table. + /// The new values. + /// The where clause. + /// The parameters. + /// The expected row count. + /// The options. + public SqlServerUpdateSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, string whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) { - readonly int? m_ExpectedRowCount; - readonly object? m_NewValues; - readonly UpdateOptions m_Options; - readonly IEnumerable? m_Parameters; - readonly SqlServerTableOrViewMetadata m_Table; - readonly object? m_UpdateArgumentValue; - readonly string? m_UpdateExpression; - FilterOptions m_FilterOptions; - object? m_FilterValue; - object? m_WhereArgumentValue; - string? m_WhereClause; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The where clause. - /// The parameters. - /// The expected row count. - /// The options. - public SqlServerUpdateSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, string whereClause, IEnumerable parameters, int? expectedRowCount, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); - - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_WhereClause = whereClause; - m_ExpectedRowCount = expectedRowCount; - m_Options = options; - m_Parameters = parameters; - } + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); + + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_WhereClause = whereClause; + m_ExpectedRowCount = expectedRowCount; + m_Options = options; + m_Parameters = parameters; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The new values. - /// The options. - /// Cannot use Key attributes with this operation. - public SqlServerUpdateSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The new values. + /// The options. + /// Cannot use Key attributes with this operation. + public SqlServerUpdateSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, object? newValues, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_NewValues = newValues; - m_Options = options; - } + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_NewValues = newValues; + m_Options = options; + } - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the table. - /// The update expression. - /// The update argument value. - /// The options. - /// Cannot use Key attributes with this operation. - public SqlServerUpdateSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) - { - if (options.HasFlag(UpdateOptions.UseKeyAttribute)) - throw new NotSupportedException("Cannot use Key attributes with this operation."); + /// + /// Initializes a new instance of the class. + /// + /// The data source. + /// Name of the table. + /// The update expression. + /// The update argument value. + /// The options. + /// Cannot use Key attributes with this operation. + public SqlServerUpdateSet(SqlServerDataSourceBase dataSource, SqlServerObjectName tableName, string updateExpression, object? updateArgumentValue, UpdateOptions options) : base(dataSource) + { + if (options.HasFlag(UpdateOptions.UseKeyAttribute)) + throw new NotSupportedException("Cannot use Key attributes with this operation."); - m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); - m_UpdateExpression = updateExpression; - m_Options = options; - m_UpdateArgumentValue = updateArgumentValue; - } + m_Table = dataSource.DatabaseMetadata.GetTableOrView(tableName); + m_UpdateExpression = updateExpression; + m_Options = options; + m_UpdateArgumentValue = updateArgumentValue; + } - /// - /// Applies this command to all rows. - /// - /// - public override UpdateSetDbCommandBuilder All() - { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; - } + /// + /// Applies this command to all rows. + /// + /// + public override UpdateSetDbCommandBuilder All() + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } - /// - /// Prepares the command for execution by generating any necessary SQL. - /// - /// The materializer. - /// ExecutionToken<TCommand>. - public override CommandExecutionToken Prepare(Materializer materializer) - { - if (materializer == null) - throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); - - SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); - SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); - - var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); - var desiredColumns = materializer.DesiredColumns(); - sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, desiredColumns == Materializer.NoColumns); - sqlBuilder.ApplyDesiredColumns(desiredColumns); - - var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; - - var sql = new StringBuilder(); - string? header; - string? intoClause; - string? footer; - - sqlBuilder.UseTableVariable(m_Table, out header, out intoClause, out footer); - - sql.Append(header); - sql.Append($"UPDATE {m_Table.Name.ToQuotedString()}"); - - var parameters = new List(); - - if (m_UpdateExpression == null) - { - sqlBuilder.BuildSetClause(sql, " SET ", null, null); - } - else - { - sql.Append(" SET " + m_UpdateExpression); - parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); - } - - sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); - if (m_FilterValue != null) - { - sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); - - parameters.AddRange(sqlBuilder.GetParameters()); - } - else if (!string.IsNullOrWhiteSpace(m_WhereClause)) - { - sql.Append(" WHERE " + m_WhereClause); - - parameters.AddRange(sqlBuilder.GetParameters()); - parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); - } - else - { - parameters.AddRange(sqlBuilder.GetParameters()); - } - sql.Append(";"); - sql.Append(footer); - - if (m_Parameters != null) - parameters.AddRange(m_Parameters); - - return new SqlServerCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); - } + /// + /// Prepares the command for execution by generating any necessary SQL. + /// + /// The materializer. + /// ExecutionToken<TCommand>. + public override CommandExecutionToken Prepare(Materializer materializer) + { + if (materializer == null) + throw new ArgumentNullException(nameof(materializer), $"{nameof(materializer)} is null."); + + SqlBuilder.CheckForOverlaps(m_NewValues, m_WhereArgumentValue, "The same parameter '{0}' appears in both the newValue object and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_NewValues, m_FilterValue, "The same parameter '{0}' appears in both the newValue object and the filter object. Use an update expression or where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_WhereArgumentValue, "The same parameter '{0}' appears in both the update expression argument and the where clause argument. Rename the parameter in the where expression to resolve the conflict."); + SqlBuilder.CheckForOverlaps(m_UpdateArgumentValue, m_FilterValue, "The same parameter '{0}' appears in both the update expression argument and the filter object. Use an update expression or where expression to resolve the conflict."); + + var sqlBuilder = m_Table.CreateSqlBuilder(StrictMode); + var desiredColumns = materializer.DesiredColumns(); + sqlBuilder.ApplyArgumentValue(DataSource, m_NewValues, m_Options, desiredColumns == Materializer.NoColumns); + sqlBuilder.ApplyDesiredColumns(desiredColumns); + + var prefix = m_Options.HasFlag(UpdateOptions.ReturnOldValues) ? "Deleted." : "Inserted."; + + var sql = new StringBuilder(); - /// - /// Returns the column associated with the column name. - /// - /// Name of the column. - /// - /// - /// If the column name was not found, this will return null - /// - public override ColumnMetadata? TryGetColumn(string columnName) + sqlBuilder.UseTableVariable(m_Table, out var header, out var intoClause, out var footer); + + sql.Append(header); + sql.Append($"UPDATE {m_Table.Name.ToQuotedString()}"); + + var parameters = new List(); + + if (m_UpdateExpression == null) { - return m_Table.Columns.TryGetColumn(columnName); + sqlBuilder.BuildSetClause(sql, " SET ", null, null); } - - /// - /// Returns a list of columns known to be non-nullable. - /// - /// - /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. - /// - /// - /// This is used by materializers to skip IsNull checks. - /// - public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; - - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The filter value. - /// The filter options. - public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + else { - m_WhereClause = null; - m_WhereArgumentValue = null; - m_FilterValue = filterValue; - m_FilterOptions = filterOptions; - return this; + sql.Append(" SET " + m_UpdateExpression); + parameters.AddRange(SqlBuilder.GetParameters(m_UpdateArgumentValue)); } - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + sqlBuilder.BuildSelectClause(sql, " OUTPUT ", prefix, intoClause); + if (m_FilterValue != null) { - m_WhereClause = whereClause; - m_WhereArgumentValue = null; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + sql.Append(" WHERE " + sqlBuilder.ApplyFilterValue(m_FilterValue, m_FilterOptions)); + + parameters.AddRange(sqlBuilder.GetParameters()); } + else if (!string.IsNullOrWhiteSpace(m_WhereClause)) + { + sql.Append(" WHERE " + m_WhereClause); - /// - /// Adds (or replaces) the filter on this command builder. - /// - /// The where clause. - /// The argument value. - /// - public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + parameters.AddRange(sqlBuilder.GetParameters()); + parameters.AddRange(SqlBuilder.GetParameters(m_WhereArgumentValue)); + } + else { - m_WhereClause = whereClause; - m_WhereArgumentValue = argumentValue; - m_FilterValue = null; - m_FilterOptions = FilterOptions.None; - return this; + parameters.AddRange(sqlBuilder.GetParameters()); } + sql.Append(";"); + sql.Append(footer); + + if (m_Parameters != null) + parameters.AddRange(m_Parameters); + + return new SqlServerCommandExecutionToken(DataSource, "Update " + m_Table.Name, sql.ToString(), parameters).CheckUpdateRowCount(m_Options, m_ExpectedRowCount); + } + + /// + /// Returns the column associated with the column name. + /// + /// Name of the column. + /// + /// + /// If the column name was not found, this will return null + /// + public override ColumnMetadata? TryGetColumn(string columnName) + { + return m_Table.Columns.TryGetColumn(columnName); + } + + /// + /// Returns a list of columns known to be non-nullable. + /// + /// + /// If the command builder doesn't know which columns are non-nullable, an empty list will be returned. + /// + /// + /// This is used by materializers to skip IsNull checks. + /// + public override IReadOnlyList TryGetNonNullableColumns() => m_Table.NonNullableColumns; + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The filter value. + /// The filter options. + public override UpdateSetDbCommandBuilder WithFilter(object filterValue, FilterOptions filterOptions = FilterOptions.None) + { + m_WhereClause = null; + m_WhereArgumentValue = null; + m_FilterValue = filterValue; + m_FilterOptions = filterOptions; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = null; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; + } + + /// + /// Adds (or replaces) the filter on this command builder. + /// + /// The where clause. + /// The argument value. + /// + public override UpdateSetDbCommandBuilder WithFilter(string whereClause, object? argumentValue) + { + m_WhereClause = whereClause; + m_WhereArgumentValue = argumentValue; + m_FilterValue = null; + m_FilterOptions = FilterOptions.None; + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer.cs index fa9533129..a9a454ee5 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer.cs @@ -1,16 +1,14 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.SqlServer.CommandBuilders; -namespace Tortuga.Chain.SqlServer.Materializers +namespace Tortuga.Chain.SqlServer.Materializers; + +internal static class WaitForChangeMaterializer { - internal static class WaitForChangeMaterializer + internal static Task GenerateTask(TCommandBuilder commandBuilder, CancellationToken cancellationToken, object? state) + where TCommandBuilder : DbCommandBuilder, ISupportsChangeListener { - internal static Task GenerateTask(TCommandBuilder commandBuilder, CancellationToken cancellationToken, object? state) - where TCommandBuilder : DbCommandBuilder, ISupportsChangeListener - { - var materializer = new WaitForChangeMaterializer(commandBuilder); - return materializer.GenerateTask(cancellationToken, state); - } + var materializer = new WaitForChangeMaterializer(commandBuilder); + return materializer.GenerateTask(cancellationToken, state); } } - diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer`1.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer`1.cs index 453976057..1a794fb1e 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer`1.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Materializers/WaitForChangeMaterializer`1.cs @@ -2,34 +2,32 @@ using Tortuga.Chain.Materializers; using Tortuga.Chain.SqlServer.CommandBuilders; -namespace Tortuga.Chain.SqlServer.Materializers +namespace Tortuga.Chain.SqlServer.Materializers; + +internal class WaitForChangeMaterializer : Materializer + where TCommandBuilder : DbCommandBuilder, ISupportsChangeListener { - internal class WaitForChangeMaterializer : Materializer - where TCommandBuilder : DbCommandBuilder, ISupportsChangeListener + /// + /// Initializes a new instance of the class. + /// + /// The associated command builder. + public WaitForChangeMaterializer(TCommandBuilder commandBuilder) + : base(commandBuilder) + { } + + internal Task GenerateTask(CancellationToken cancellationToken, object? state) { - /// - /// Initializes a new instance of the class. - /// - /// The associated command builder. - public WaitForChangeMaterializer(TCommandBuilder commandBuilder) - : base(commandBuilder) - { } - - internal Task GenerateTask(CancellationToken cancellationToken, object? state) - { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); - var token = ((ISupportsChangeListener)CommandBuilder).Prepare(this); + var token = ((ISupportsChangeListener)CommandBuilder).Prepare(this); - token.AddChangeListener((s, e) => tcs.TrySetResult(e)); + token.AddChangeListener((s, e) => tcs.TrySetResult(e)); - if (cancellationToken.CanBeCanceled) - cancellationToken.Register(() => tcs.TrySetCanceled()); + if (cancellationToken.CanBeCanceled) + cancellationToken.Register(() => tcs.TrySetCanceled()); - token.ExecuteAsync(async cmd => await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state); + token.ExecuteAsync(async cmd => await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false), cancellationToken, state); - return tcs.Task; - } + return tcs.Task; } } - diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerAppenders.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerAppenders.cs index 137ebdad4..f7199e8ce 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerAppenders.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerAppenders.cs @@ -2,62 +2,60 @@ using Tortuga.Chain.SqlServer.Appenders; using Tortuga.Chain.SqlServer.CommandBuilders; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerAppenders. +/// +public static class SqlServerAppenders { /// - /// Class SqlServerAppenders. + /// Return the approximate row count using the APPROX_COUNT_DISTINCT function. /// - public static class SqlServerAppenders + /// The table database command. + /// This is only available on tables with a single primary key. + public static ILink AsCountDistinctApproximate(this TableDbCommandBuilder tableDbCommand) { - /// - /// Return the approximate row count using the APPROX_COUNT_DISTINCT function. - /// - /// The table database command. - /// This is only available on tables with a single primary key. - public static ILink AsCountDistinctApproximate(this TableDbCommandBuilder tableDbCommand) - { - if (tableDbCommand == null) - throw new ArgumentNullException(nameof(tableDbCommand), $"{nameof(tableDbCommand)} is null."); - - return ((ISupportsApproximateCount)tableDbCommand).AsCountApproximate(); - } + if (tableDbCommand == null) + throw new ArgumentNullException(nameof(tableDbCommand), $"{nameof(tableDbCommand)} is null."); - /// - /// Return the approximate distinct count using the APPROX_COUNT_DISTINCT function. - /// - /// The table database command. - /// Name of the column. - public static ILink AsCountDistinctApproximate(this TableDbCommandBuilder tableDbCommand, string columnName) - { - if (tableDbCommand == null) - throw new ArgumentNullException(nameof(tableDbCommand), $"{nameof(tableDbCommand)} is null."); + return ((ISupportsApproximateCount)tableDbCommand).AsCountApproximate(); + } - return ((ISupportsApproximateCount)tableDbCommand).AsCountApproximate(columnName); - } + /// + /// Return the approximate distinct count using the APPROX_COUNT_DISTINCT function. + /// + /// The table database command. + /// Name of the column. + public static ILink AsCountDistinctApproximate(this TableDbCommandBuilder tableDbCommand, string columnName) + { + if (tableDbCommand == null) + throw new ArgumentNullException(nameof(tableDbCommand), $"{nameof(tableDbCommand)} is null."); - /// - /// Attaches a SQL Server dependency change listener to this operation. - /// - /// The type of the t result type. - /// The previous link. - /// The event handler to fire when the underlying data changes. - /// Tortuga.Chain.Core.ILink<TResult>. - /// This will only work for operations against non-transactional SQL Server data sources that also comform to the rules about using SQL Dependency. - public static ILink WithChangeNotification(this ILink previousLink, OnChangeEventHandler eventHandler) - { - return new NotifyChangeAppender(previousLink, eventHandler); - } + return ((ISupportsApproximateCount)tableDbCommand).AsCountApproximate(columnName); + } - /// - /// Attaches a SQL Server dependency change listener to this operation that will automatically invalidate the cache. - /// - /// The type of the result. - /// The previous link. - /// - public static ILink AutoInvalidate(this ICacheLink previousLink) - { - return new NotifyChangeAppender(previousLink, (s, e) => previousLink.Invalidate()); - } + /// + /// Attaches a SQL Server dependency change listener to this operation that will automatically invalidate the cache. + /// + /// The type of the result. + /// The previous link. + /// + public static ILink AutoInvalidate(this ICacheLink previousLink) + { + return new NotifyChangeAppender(previousLink, (s, e) => previousLink.Invalidate()); + } + /// + /// Attaches a SQL Server dependency change listener to this operation. + /// + /// The type of the t result type. + /// The previous link. + /// The event handler to fire when the underlying data changes. + /// Tortuga.Chain.Core.ILink<TResult>. + /// This will only work for operations against non-transactional SQL Server data sources that also comform to the rules about using SQL Dependency. + public static ILink WithChangeNotification(this ILink previousLink, OnChangeEventHandler eventHandler) + { + return new NotifyChangeAppender(previousLink, eventHandler); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerCommandExecutionToken.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerCommandExecutionToken.cs index ff1c10633..692a8c937 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerCommandExecutionToken.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerCommandExecutionToken.cs @@ -1,61 +1,59 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// An execution token specific to Sql Server. +/// +public sealed class SqlServerCommandExecutionToken : CommandExecutionToken { + OnChangeEventHandler? m_OnChangeEventHandler; + /// - /// An execution token specific to Sql Server. + /// Initializes a new instance of the class. /// - public sealed class SqlServerCommandExecutionToken : CommandExecutionToken + /// The data source. + /// Name of the operation. This is used for logging. + /// The SQL to be executed. + /// The parameters. + /// Type of the command. + public SqlServerCommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) + : base(dataSource, operationName, commandText, parameters, commandType) { - OnChangeEventHandler? m_OnChangeEventHandler; - - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. This is used for logging. - /// The SQL to be executed. - /// The parameters. - /// Type of the command. - public SqlServerCommandExecutionToken(ICommandDataSource dataSource, string operationName, string commandText, IReadOnlyList parameters, CommandType commandType = CommandType.Text) - : base(dataSource, operationName, commandText, parameters, commandType) - { - } - + } - /// - /// Adds a SQL Dependency based change listener. - /// - /// The event handler. - /// This requires SQL Dependency to be active. - public void AddChangeListener(OnChangeEventHandler eventHandler) - { - if (eventHandler == null) - throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); + /// + /// Adds a SQL Dependency based change listener. + /// + /// The event handler. + /// This requires SQL Dependency to be active. + public void AddChangeListener(OnChangeEventHandler eventHandler) + { + if (eventHandler == null) + throw new ArgumentNullException(nameof(eventHandler), $"{nameof(eventHandler)} is null."); - var disp = DataSource as SqlServerDataSource; - if (disp == null) - throw new InvalidOperationException("Change listeners can only be added to non-transactional data sources."); - if (!disp.IsSqlDependencyActive) - throw new InvalidOperationException("SQL Dependency is not active on the associated data source."); + var disp = DataSource as SqlServerDataSource; + if (disp == null) + throw new InvalidOperationException("Change listeners can only be added to non-transactional data sources."); + if (!disp.IsSqlDependencyActive) + throw new InvalidOperationException("SQL Dependency is not active on the associated data source."); - m_OnChangeEventHandler += eventHandler; + m_OnChangeEventHandler += eventHandler; - return; - } + return; + } - /// - /// Subclasses can override this method to change the command object after the command text and parameters are loaded. - /// - protected override void OnBuildCommand(SqlCommand command) + /// + /// Subclasses can override this method to change the command object after the command text and parameters are loaded. + /// + protected override void OnBuildCommand(SqlCommand command) + { + base.OnBuildCommand(command); + if (m_OnChangeEventHandler != null) { - base.OnBuildCommand(command); - if (m_OnChangeEventHandler != null) - { - var sd = new SqlDependency(command); - sd.OnChange += m_OnChangeEventHandler; - } + var sd = new SqlDependency(command); + sd.OnChange += m_OnChangeEventHandler; } } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.CommandBuilders.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.CommandBuilders.cs index 11cd3a5a5..ccd4cc52b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.CommandBuilders.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.CommandBuilders.cs @@ -4,163 +4,158 @@ using Tortuga.Chain.CommandBuilders; using Tortuga.Chain.SqlServer.CommandBuilders; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +partial class SqlServerDataSourceBase { - partial class SqlServerDataSourceBase + /// + /// Inserts the batch of records as one operation. + /// + /// Name of the table. + /// Name of the table type. + /// The data table. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + public MultipleRowDbCommandBuilder InsertBatch(SqlServerObjectName tableName, DataTable dataTable, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) { + return new SqlServerInsertBatchTable(this, tableName, dataTable, tableTypeName, options); + } + /// + /// Inserts the batch of records as one operation. + /// + /// Name of the table. + /// Name of the table type. + /// The data reader. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + public MultipleRowDbCommandBuilder InsertBatch(SqlServerObjectName tableName, DbDataReader dataReader, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) + { + return new SqlServerInsertBatchTable(this, tableName, dataReader, tableTypeName, options); + } - /// - /// Inserts the batch of records as one operation. - /// - /// Name of the table. - /// Name of the table type. - /// The data table. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public MultipleRowDbCommandBuilder InsertBatch(SqlServerObjectName tableName, DataTable dataTable, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) - { - return new SqlServerInsertBatchTable(this, tableName, dataTable, tableTypeName, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// Name of the table. - /// Name of the table type. - /// The data reader. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - public MultipleRowDbCommandBuilder InsertBatch(SqlServerObjectName tableName, DbDataReader dataReader, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) - { - return new SqlServerInsertBatchTable(this, tableName, dataReader, tableTypeName, options); - } - - /// - /// Inserts the batch of records as one operation. - /// - /// - /// Name of the table. - /// Name of the table type. - /// The objects. - /// The options. - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - public MultipleRowDbCommandBuilder InsertBatch(SqlServerObjectName tableName, IEnumerable objects, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) - { - var tableType = DatabaseMetadata.GetUserDefinedTableType(tableTypeName); - return new SqlServerInsertBatchTable(this, tableName, new ObjectDataReader(tableType, objects), tableTypeName, options); - } - - /// - /// Inserts the batch of records as one operation.. - /// - /// The type of the object. - /// Name of the table type. - /// The objects. - /// The options. - /// - /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. - /// - public MultipleRowDbCommandBuilder InsertBatch(IEnumerable objects, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) where TObject : class - { - return InsertBatch(DatabaseMetadata.GetTableOrViewFromClass().Name, objects, tableTypeName, options); - } - - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data table. - /// The options. - /// SqlServerInsertBulk. - [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public SqlServerInsertBulk InsertBulk(SqlServerObjectName tableName, DataTable dataTable, SqlBulkCopyOptions options) - { - return InsertBulk(tableName, dataTable).WithOptions(options); - } + /// + /// Inserts the batch of records as one operation. + /// + /// + /// Name of the table. + /// Name of the table type. + /// The objects. + /// The options. + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + public MultipleRowDbCommandBuilder InsertBatch(SqlServerObjectName tableName, IEnumerable objects, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) + { + var tableType = DatabaseMetadata.GetUserDefinedTableType(tableTypeName); + return new SqlServerInsertBatchTable(this, tableName, new ObjectDataReader(tableType, objects), tableTypeName, options); + } - /// - /// Inserts the batch of records using bulk insert. - /// - /// Name of the table. - /// The data reader. - /// The options. - /// SqlServerInsertBulk. - [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public SqlServerInsertBulk InsertBulk(SqlServerObjectName tableName, IDataReader dataReader, SqlBulkCopyOptions options) - { - return InsertBulk(tableName, dataReader).WithOptions(options); - } + /// + /// Inserts the batch of records as one operation.. + /// + /// The type of the object. + /// Name of the table type. + /// The objects. + /// The options. + /// + /// MultipleRowDbCommandBuilder<SqlCommand, SqlParameter>. + /// + public MultipleRowDbCommandBuilder InsertBatch(IEnumerable objects, SqlServerObjectName tableTypeName, InsertOptions options = InsertOptions.None) where TObject : class + { + return InsertBatch(DatabaseMetadata.GetTableOrViewFromClass().Name, objects, tableTypeName, options); + } - /// - /// Inserts the batch of records using bulk insert. - /// - /// - /// Name of the table. - /// The objects. - /// The options. - /// SqlServerInsertBulk. - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public SqlServerInsertBulk InsertBulk(SqlServerObjectName tableName, IEnumerable objects, SqlBulkCopyOptions options) where TObject : class - { - return InsertBulk(tableName, objects).WithOptions(options); - } + /// + /// Inserts the batch of records using bulk insert. + /// + /// Name of the table. + /// The data table. + /// The options. + /// SqlServerInsertBulk. + [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public SqlServerInsertBulk InsertBulk(SqlServerObjectName tableName, DataTable dataTable, SqlBulkCopyOptions options) + { + return InsertBulk(tableName, dataTable).WithOptions(options); + } - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data table. - /// The options. - /// - /// SqlServerInsertBulk. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public SqlServerInsertBulk InsertBulk(DataTable dataTable, SqlBulkCopyOptions options) where TObject : class - { - return InsertBulk(dataTable).WithOptions(options); - } + /// + /// Inserts the batch of records using bulk insert. + /// + /// Name of the table. + /// The data reader. + /// The options. + /// SqlServerInsertBulk. + [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public SqlServerInsertBulk InsertBulk(SqlServerObjectName tableName, IDataReader dataReader, SqlBulkCopyOptions options) + { + return InsertBulk(tableName, dataReader).WithOptions(options); + } - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The data reader. - /// The options. - /// - /// SqlServerInsertBulk. - /// - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public SqlServerInsertBulk InsertBulk(IDataReader dataReader, SqlBulkCopyOptions options) where TObject : class - { - return InsertBulk(dataReader).WithOptions(options); - } + /// + /// Inserts the batch of records using bulk insert. + /// + /// + /// Name of the table. + /// The objects. + /// The options. + /// SqlServerInsertBulk. + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public SqlServerInsertBulk InsertBulk(SqlServerObjectName tableName, IEnumerable objects, SqlBulkCopyOptions options) where TObject : class + { + return InsertBulk(tableName, objects).WithOptions(options); + } - /// - /// Inserts the batch of records using bulk insert. - /// - /// The type of the object. - /// The objects. - /// The options. - /// - /// SqlServerInsertBulk. - /// - [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public SqlServerInsertBulk InsertBulk(IEnumerable objects, SqlBulkCopyOptions options) where TObject : class - { - return InsertBulk(objects).WithOptions(options); - } + /// + /// Inserts the batch of records using bulk insert. + /// + /// The type of the object. + /// The data table. + /// The options. + /// + /// SqlServerInsertBulk. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public SqlServerInsertBulk InsertBulk(DataTable dataTable, SqlBulkCopyOptions options) where TObject : class + { + return InsertBulk(dataTable).WithOptions(options); + } + /// + /// Inserts the batch of records using bulk insert. + /// + /// The type of the object. + /// The data reader. + /// The options. + /// + /// SqlServerInsertBulk. + /// + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public SqlServerInsertBulk InsertBulk(IDataReader dataReader, SqlBulkCopyOptions options) where TObject : class + { + return InsertBulk(dataReader).WithOptions(options); + } + /// + /// Inserts the batch of records using bulk insert. + /// + /// The type of the object. + /// The objects. + /// The options. + /// + /// SqlServerInsertBulk. + /// + [Obsolete("Use InsertBulk(...).WithOptions(SqlBulkCopyOptions) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public SqlServerInsertBulk InsertBulk(IEnumerable objects, SqlBulkCopyOptions options) where TObject : class + { + return InsertBulk(objects).WithOptions(options); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.Traits.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.Traits.cs index 1e93aa84d..ed8c4941b 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.Traits.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceBase.Traits.cs @@ -8,8 +8,8 @@ namespace Tortuga.Chain.SqlServer; -[UseTrait(typeof(SupportsDeleteAllTrait))] -[UseTrait(typeof(SupportsTruncateTrait))] +[UseTrait(typeof(SupportsDeleteAllTrait))] +[UseTrait(typeof(SupportsTruncateTrait))] [UseTrait(typeof(SupportsSqlQueriesTrait))] [UseTrait(typeof(SupportsInsertBatchTrait>))] @@ -27,6 +27,7 @@ namespace Tortuga.Chain.SqlServer; [UseTrait(typeof(SupportsScalarFunctionTrait))] [UseTrait(typeof(SupportsProcedureTrait))] [UseTrait(typeof(SupportsTableFunctionTrait))] +[UseTrait(typeof(SupportsGetByColumnListTrait))] partial class SqlServerDataSourceBase : ICrudDataSource, IAdvancedCrudDataSource { DatabaseMetadataCache ICommandHelper.DatabaseMetadata => DatabaseMetadata; @@ -99,7 +100,7 @@ TableDbCommandBuilder(this, tableOrViewName, filterValue, filterOptions); } - SingleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) + MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKey(AbstractObjectName tableName, ColumnMetadata keyColumn, TKey key) where TObject : class { var where = keyColumn.SqlName + " = @Param0"; @@ -111,7 +112,6 @@ SingleRowDbCommandBuilder IGetByKeyHelper(this, tableName, where, parameters); - } MultipleRowDbCommandBuilder IGetByKeyHelper.OnGetByKeyList(AbstractObjectName tableName, ColumnMetadata keyColumn, IEnumerable keys) where TObject : class @@ -133,7 +133,6 @@ MultipleRowDbCommandBuilder IGetByKeyHelper< } return new MultipleRowDbCommandBuilder(new SqlServerTableOrView(this, tableName, where, parameters)); - } DbCommandBuilder IInsertBatchHelper.OnInsertBatch(AbstractObjectName tableName, IEnumerable objects, InsertOptions options) @@ -164,7 +163,6 @@ ObjectDbCommandBuilder IUpsertHel MultipleRowDbCommandBuilder IUpdateDeleteByKeyHelper.OnUpdateByKeyList(AbstractObjectName tableName, TArgument newValues, IEnumerable keys, UpdateOptions options) { - var primaryKeys = DatabaseMetadata.GetTableOrView(tableName).PrimaryKeyColumns; if (primaryKeys.Count != 1) throw new MappingException($"{nameof(UpdateByKeyList)} operation isn't allowed on {tableName} because it doesn't have a single primary key."); @@ -238,4 +236,4 @@ private partial TableDbCommandBuilder +/// Class SqlServerDataSourceBase. +/// +public abstract partial class SqlServerDataSourceBase : DataSource { /// - /// Class SqlServerDataSourceBase. + /// Initializes a new instance of the class. /// - public abstract partial class SqlServerDataSourceBase : DataSource + /// Optional settings value. + protected SqlServerDataSourceBase(SqlServerDataSourceSettings? settings) : base(settings) { - /// - /// Initializes a new instance of the class. - /// - /// Optional settings value. - protected SqlServerDataSourceBase(SqlServerDataSourceSettings? settings) : base(settings) - { - } + } + + /// + /// Gets the database metadata. + /// + /// The database metadata. + public abstract new SqlServerMetadataCache DatabaseMetadata { get; } - /// - /// Gets the database metadata. - /// - /// The database metadata. - public abstract new SqlServerMetadataCache DatabaseMetadata { get; } + /// + /// Called when Database.DatabaseMetadata is invoked. + /// + /// + protected override IDatabaseMetadataCache OnGetDatabaseMetadata() => DatabaseMetadata; - /// - /// Called when Database.DatabaseMetadata is invoked. - /// - /// - protected override IDatabaseMetadataCache OnGetDatabaseMetadata() => DatabaseMetadata; + private protected void CommandFixup(CommandExecutionToken executionToken, SqlCommand cmd) + { +#if SQL_SERVER_MDS + if (!executionToken.HasOutputParameters) + cmd.EnableOptimizedParameterBinding = true; +#endif } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceSettings.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceSettings.cs index 1d891c6a6..6368c5560 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceSettings.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerDataSourceSettings.cs @@ -1,64 +1,63 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.DataSources; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// This allows overriding connection options. +/// +public class SqlServerDataSourceSettings : DataSourceSettings { /// - /// This allows overriding connection options. + /// Initializes a new instance of the class. /// - public class SqlServerDataSourceSettings : DataSourceSettings + public SqlServerDataSourceSettings() { - /// - /// Initializes a new instance of the class. - /// - public SqlServerDataSourceSettings() - { - } + } #if SQL_SERVER_SDS || SQL_SERVER_MDS - internal SqlServerDataSourceSettings(SqlServerDataSource dataSource, bool forwardEvents = false) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - - DefaultCommandTimeout = dataSource.DefaultCommandTimeout; - StrictMode = dataSource.StrictMode; - SequentialAccessMode = dataSource.SequentialAccessMode; - SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; - SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; - ArithAbort = dataSource.ArithAbort; - XactAbort = dataSource.XactAbort; - } + internal SqlServerDataSourceSettings(SqlServerDataSource dataSource, bool forwardEvents = false) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + + DefaultCommandTimeout = dataSource.DefaultCommandTimeout; + StrictMode = dataSource.StrictMode; + SequentialAccessMode = dataSource.SequentialAccessMode; + SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; + SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; + ArithAbort = dataSource.ArithAbort; + XactAbort = dataSource.XactAbort; + } #elif SQL_SERVER_OLEDB - internal SqlServerDataSourceSettings(OleDbSqlServerDataSource dataSource, bool forwardEvents = false) - { - if (dataSource == null) - throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - - DefaultCommandTimeout = dataSource.DefaultCommandTimeout; - StrictMode = dataSource.StrictMode; - SequentialAccessMode = dataSource.SequentialAccessMode; - SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; - ArithAbort = dataSource.ArithAbort; - XactAbort = dataSource.XactAbort; - } + internal SqlServerDataSourceSettings(OleDbSqlServerDataSource dataSource, bool forwardEvents = false) + { + if (dataSource == null) + throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + + DefaultCommandTimeout = dataSource.DefaultCommandTimeout; + StrictMode = dataSource.StrictMode; + SequentialAccessMode = dataSource.SequentialAccessMode; + SuppressGlobalEvents = dataSource.SuppressGlobalEvents || forwardEvents; + ArithAbort = dataSource.ArithAbort; + XactAbort = dataSource.XactAbort; + } #endif - /// - /// Terminates a query when an overflow or divide-by-zero error occurs during query execution. - /// - /// Microsoft recommends setting ArithAbort=On for all connections. To avoid an additional round-trip to the server, do this at the server level instead of at the connection level. - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool? ArithAbort { get; set; } + /// + /// Terminates a query when an overflow or divide-by-zero error occurs during query execution. + /// + /// Microsoft recommends setting ArithAbort=On for all connections. To avoid an additional round-trip to the server, do this at the server level instead of at the connection level. + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool? ArithAbort { get; set; } - /// - /// Rolls back a transaction if a Transact-SQL statement raises a run-time error. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] - public bool? XactAbort { get; set; } - } + /// + /// Rolls back a transaction if a Transact-SQL statement raises a run-time error. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] + public bool? XactAbort { get; set; } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerEffectiveSettings.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerEffectiveSettings.cs index 39eb8f1a5..30e26d524 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerEffectiveSettings.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerEffectiveSettings.cs @@ -1,102 +1,101 @@ using System.Diagnostics.CodeAnalysis; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// This contains the connection options that are currently in effect. +/// +public class SqlServerEffectiveSettings { + int m_Options; + + internal SqlServerEffectiveSettings() + { + } + + /// + /// ANSI_NULL_DFLT_OFF. Alters the session's behavior not to use ANSI compatibility for nullability. New columns defined without explicit nullability do not allow nulls. + /// + public bool AnsiNullDefaultOff { get { return (m_Options & 2048) > 0; } } + + /// + /// ANSI_NULL_DFLT_ON. Alters the session's behavior to use ANSI compatibility for nullability. New columns defined without explicit nullability are defined to allow nulls. + /// + public bool AnsiNullDefaultOn { get { return (m_Options & 1024) > 0; } } + + /// + /// ANSI_NULLS. Controls NULL handling when using equality operators. + /// + public bool AnsiNulls { get { return (m_Options & 32) > 0; } } + + /// + /// ANSI_PADDING. Controls padding of fixed-length variables. + /// + public bool AnsiPadding { get { return (m_Options & 16) > 0; } } + + /// + /// ANSI_WARNINGS. Controls truncation and NULL in aggregate warnings. + /// + public bool AnsiWarning { get { return (m_Options & 8) > 0; } } + + /// + /// ARITHABORT. Terminates a query when an overflow or divide-by-zero error occurs during query execution. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool ArithAbort { get { return (m_Options & 64) > 0; } } + + /// + /// ARITHIGNORE. Returns NULL when an overflow or divide-by-zero error occurs during a query. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool ArithIgnore { get { return (m_Options & 128) > 0; } } + + /// + /// CONCAT_NULL_YIELDS_NULL. Returns NULL when concatenating a NULL value with a string. + /// + public bool ConcatNullYieldsNull { get { return (m_Options & 4096) > 0; } } + + /// + /// CURSOR_CLOSE_ON_COMMIT. Controls behavior of cursors after a commit operation has been performed. + /// + public bool CursorCloseOnCommit { get { return (m_Options & 4) > 0; } } + + /// + /// DISABLE_DEF_CNST_CHK. Controls interim or deferred constraint checking. + /// + public bool DisableDeferredConstraintChecking { get { return (m_Options & 1) > 0; } } + + /// + /// NOCOUNT. Turns off the message returned at the end of each statement that states how many rows were affected. + /// + public bool NoCount { get { return (m_Options & 512) > 0; } } + + /// + /// NUMERIC_ROUNDABORT. Generates an error when a loss of precision occurs in an expression. + /// + public bool NumericRoundAbort { get { return (m_Options & 8192) > 0; } } + + /// + /// QUOTED_IDENTIFIER. Differentiates between single and double quotation marks when evaluating an expression. + /// + public bool QuotedIdentifier { get { return (m_Options & 256) > 0; } } + /// - /// This contains the connection options that are currently in effect. + /// XACT_ABORT. Rolls back a transaction if a Transact-SQL statement raises a run-time error. /// - public class SqlServerEffectiveSettings + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] + public bool XactAbort { get { return (m_Options & 16384) > 0; } } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + internal void Reload(SqlConnection connection, SqlTransaction? transaction) + { + using (var cmd = new SqlCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) + m_Options = (int)cmd.ExecuteScalar(); + } + + internal async Task ReloadAsync(SqlConnection connection, SqlTransaction? transaction) { - int m_Options; - - internal SqlServerEffectiveSettings() - { - } - - /// - /// ANSI_NULL_DFLT_OFF. Alters the session's behavior not to use ANSI compatibility for nullability. New columns defined without explicit nullability do not allow nulls. - /// - public bool AnsiNullDefaultOff { get { return (m_Options & 2048) > 0; } } - - /// - /// ANSI_NULL_DFLT_ON. Alters the session's behavior to use ANSI compatibility for nullability. New columns defined without explicit nullability are defined to allow nulls. - /// - public bool AnsiNullDefaultOn { get { return (m_Options & 1024) > 0; } } - - /// - /// ANSI_NULLS. Controls NULL handling when using equality operators. - /// - public bool AnsiNulls { get { return (m_Options & 32) > 0; } } - - /// - /// ANSI_PADDING. Controls padding of fixed-length variables. - /// - public bool AnsiPadding { get { return (m_Options & 16) > 0; } } - - /// - /// ANSI_WARNINGS. Controls truncation and NULL in aggregate warnings. - /// - public bool AnsiWarning { get { return (m_Options & 8) > 0; } } - - /// - /// ARITHABORT. Terminates a query when an overflow or divide-by-zero error occurs during query execution. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool ArithAbort { get { return (m_Options & 64) > 0; } } - - /// - /// ARITHIGNORE. Returns NULL when an overflow or divide-by-zero error occurs during a query. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool ArithIgnore { get { return (m_Options & 128) > 0; } } - - /// - /// CONCAT_NULL_YIELDS_NULL. Returns NULL when concatenating a NULL value with a string. - /// - public bool ConcatNullYieldsNull { get { return (m_Options & 4096) > 0; } } - - /// - /// CURSOR_CLOSE_ON_COMMIT. Controls behavior of cursors after a commit operation has been performed. - /// - public bool CursorCloseOnCommit { get { return (m_Options & 4) > 0; } } - - /// - /// DISABLE_DEF_CNST_CHK. Controls interim or deferred constraint checking. - /// - public bool DisableDeferredConstraintChecking { get { return (m_Options & 1) > 0; } } - - /// - /// NOCOUNT. Turns off the message returned at the end of each statement that states how many rows were affected. - /// - public bool NoCount { get { return (m_Options & 512) > 0; } } - - /// - /// NUMERIC_ROUNDABORT. Generates an error when a loss of precision occurs in an expression. - /// - public bool NumericRoundAbort { get { return (m_Options & 8192) > 0; } } - - /// - /// QUOTED_IDENTIFIER. Differentiates between single and double quotation marks when evaluating an expression. - /// - public bool QuotedIdentifier { get { return (m_Options & 256) > 0; } } - - /// - /// XACT_ABORT. Rolls back a transaction if a Transact-SQL statement raises a run-time error. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] - public bool XactAbort { get { return (m_Options & 16384) > 0; } } - - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - internal void Reload(SqlConnection connection, SqlTransaction? transaction) - { - using (var cmd = new SqlCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) - m_Options = (int)cmd.ExecuteScalar(); - } - - internal async Task ReloadAsync(SqlConnection connection, SqlTransaction? transaction) - { - using (var cmd = new SqlCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) - m_Options = (int)(await cmd.ExecuteScalarAsync().ConfigureAwait(false))!; - } + using (var cmd = new SqlCommand("SELECT @@Options") { Connection = connection, Transaction = transaction }) + m_Options = (int)(await cmd.ExecuteScalarAsync().ConfigureAwait(false))!; } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerMetadataCache.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerMetadataCache.cs index 1c0d10109..d3bf9c63c 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerMetadataCache.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerMetadataCache.cs @@ -1,173 +1,172 @@ - -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerMetadataCache. +/// +public sealed partial class SqlServerMetadataCache { + internal readonly SqlConnectionStringBuilder m_MasterConnectionBuilder; + /// - /// Class SqlServerMetadataCache. + /// Initializes a new instance of the class. /// - public sealed partial class SqlServerMetadataCache + /// The connection builder. + public SqlServerMetadataCache(SqlConnectionStringBuilder connectionBuilder) { - /// - /// Initializes a new instance of the class. - /// - /// The connection builder. - public SqlServerMetadataCache(SqlConnectionStringBuilder connectionBuilder) - { - if (connectionBuilder == null) - throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null"); - - m_ConnectionBuilder = connectionBuilder; + if (connectionBuilder == null) + throw new ArgumentNullException(nameof(connectionBuilder), $"{nameof(connectionBuilder)} is null"); - m_MasterConnectionBuilder = new SqlConnectionStringBuilder(connectionBuilder.ConnectionString) { InitialCatalog = "master" }; - } + m_ConnectionBuilder = connectionBuilder; - internal readonly SqlConnectionStringBuilder m_MasterConnectionBuilder; + m_MasterConnectionBuilder = new SqlConnectionStringBuilder(connectionBuilder.ConnectionString) { InitialCatalog = "master" }; + } - /// - /// Returns the current database. - /// - /// - public string DatabaseName + /// + /// Returns the current database. + /// + /// + public string DatabaseName + { + get { - get + if (m_DatabaseName == null) { - if (m_DatabaseName == null) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new SqlCommand("SELECT DB_NAME () AS DatabaseName", con)) { - con.Open(); - using (var cmd = new SqlCommand("SELECT DB_NAME () AS DatabaseName", con)) - { - m_DatabaseName = (string)cmd.ExecuteScalar(); - } + m_DatabaseName = (string)cmd.ExecuteScalar(); } } - return m_DatabaseName; } + return m_DatabaseName; } + } - /// - /// This is used to decide which option overrides to set when establishing a connection. - /// - internal SqlServerEffectiveSettings? ServerDefaultSettings { get; set; } - - /// - /// Returns the user's default schema. - /// - /// - public string DefaultSchema + /// + /// Returns the user's default schema. + /// + /// + public string DefaultSchema + { + get { - get + if (m_DefaultSchema == null) { - if (m_DefaultSchema == null) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) { - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + con.Open(); + using (var cmd = new SqlCommand("SELECT SCHEMA_NAME () AS DefaultSchema", con)) { - con.Open(); - using (var cmd = new SqlCommand("SELECT SCHEMA_NAME () AS DefaultSchema", con)) - { - m_DefaultSchema = (string)cmd.ExecuteScalar(); - } + m_DefaultSchema = (string)cmd.ExecuteScalar(); } } - return m_DefaultSchema; } + return m_DefaultSchema; } + } - /// - /// Gets the indexes for a table. - /// - /// Name of the table. - /// - /// - /// This should be cached on a TableOrViewMetadata object. - /// - public override IndexMetadataCollection GetIndexesForTable(SqlServerObjectName tableName) - { - const string indexSql = @"SELECT i.name, - i.is_primary_key, - i.is_unique, - i.is_unique_constraint, + /// + /// This is used to decide which option overrides to set when establishing a connection. + /// + internal SqlServerEffectiveSettings? ServerDefaultSettings { get; set; } + + /// + /// Gets the indexes for a table. + /// + /// Name of the table. + /// + /// + /// This should be cached on a TableOrViewMetadata object. + /// + public override IndexMetadataCollection GetIndexesForTable(SqlServerObjectName tableName) + { + const string indexSql = @"SELECT i.name, + i.is_primary_key, + i.is_unique, + i.is_unique_constraint, i.index_id, - i.type, - (SELECT SUM(used_page_count) * 8 FROM sys.dm_db_partition_stats ddps WHERE ddps.object_id=i.object_id AND ddps.index_id = i.index_id) AS IndexSizeKB, - (SELECT SUM(row_count) FROM sys.dm_db_partition_stats ddps WHERE ddps.object_id=i.object_id AND ddps.index_id = i.index_id) AS [RowCount] + i.type, + (SELECT SUM(used_page_count) * 8 FROM sys.dm_db_partition_stats ddps WHERE ddps.object_id=i.object_id AND ddps.index_id = i.index_id) AS IndexSizeKB, + (SELECT SUM(row_count) FROM sys.dm_db_partition_stats ddps WHERE ddps.object_id=i.object_id AND ddps.index_id = i.index_id) AS [RowCount] FROM sys.indexes i - INNER JOIN sys.objects o - ON i.object_id = o.object_id - INNER JOIN sys.schemas s - ON o.schema_id = s.schema_id + INNER JOIN sys.objects o + ON i.object_id = o.object_id + INNER JOIN sys.schemas s + ON o.schema_id = s.schema_id WHERE o.name = @Name - AND s.name = @Schema;"; + AND s.name = @Schema;"; - var allColumns = GetColumnsForIndex(tableName); + var allColumns = GetColumnsForIndex(tableName); - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); - using (var cmd = new SqlCommand(indexSql, con)) - { - cmd.Parameters.AddWithValue("@Schema", tableName.Schema); - cmd.Parameters.AddWithValue("@Name", tableName.Name); + using (var cmd = new SqlCommand(indexSql, con)) + { + cmd.Parameters.AddWithValue("@Schema", tableName.Schema); + cmd.Parameters.AddWithValue("@Name", tableName.Name); - var results = new List>(); + var results = new List>(); - using (var reader = cmd.ExecuteReader()) + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) { - while (reader.Read()) + var is_primary_key = reader.GetBoolean("is_primary_key"); + var is_unique = reader.GetBoolean("is_unique"); + var is_unique_constraint = reader.GetBoolean("is_unique_constraint"); + var index_id = reader.GetInt32("index_id"); + var name = reader.GetStringOrNull("Name"); + var columns = new IndexColumnMetadataCollection(allColumns.Where(c => c.IndexId == index_id)); + var indexSize = reader.GetInt64("IndexSizeKB"); + var rowCount = reader.GetInt64("RowCount"); + + IndexType indexType; + switch (reader.GetByte("type")) { - var is_primary_key = reader.GetBoolean("is_primary_key"); - var is_unique = reader.GetBoolean("is_unique"); - var is_unique_constraint = reader.GetBoolean("is_unique_constraint"); - var index_id = reader.GetInt32("index_id"); - var name = reader.GetStringOrNull("Name"); - var columns = new IndexColumnMetadataCollection(allColumns.Where(c => c.IndexId == index_id)); - var indexSize = reader.GetInt64("IndexSizeKB"); - var rowCount = reader.GetInt64("RowCount"); - - IndexType indexType; - switch (reader.GetByte("type")) - { - case 0: indexType = IndexType.Heap; break; - case 1: indexType = IndexType.Clustered; break; - case 2: indexType = IndexType.Nonclustered; break; - case 3: indexType = IndexType.Xml; break; - case 4: indexType = IndexType.Spatial; break; - case 5: indexType = IndexType.ClusteredColumnstoreIndex; break; - case 6: indexType = IndexType.NonclusteredColumnstoreIndex; break; - case 7: indexType = IndexType.NonclusteredHashIndex; break; - default: indexType = IndexType.Unknown; break; - } - - results.Add(new IndexMetadata(tableName, name, is_primary_key, is_unique, is_unique_constraint, columns, indexSize, rowCount, indexType)); + case 0: indexType = IndexType.Heap; break; + case 1: indexType = IndexType.Clustered; break; + case 2: indexType = IndexType.Nonclustered; break; + case 3: indexType = IndexType.Xml; break; + case 4: indexType = IndexType.Spatial; break; + case 5: indexType = IndexType.ClusteredColumnstoreIndex; break; + case 6: indexType = IndexType.NonclusteredColumnstoreIndex; break; + case 7: indexType = IndexType.NonclusteredHashIndex; break; + default: indexType = IndexType.Unknown; break; } - return new IndexMetadataCollection(results); + results.Add(new IndexMetadata(tableName, name, is_primary_key, is_unique, is_unique_constraint, columns, indexSize, rowCount, indexType)); } + + return new IndexMetadataCollection(results); } } } + } - /// - /// Gets the detailed metadata for a table or view. - /// - /// Name of the table. - /// SqlServerTableOrViewMetadata<TDbType>. - public new SqlServerTableOrViewMetadata GetTableOrView(SqlServerObjectName tableName) - { - return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); - } + /// + /// Gets the detailed metadata for a table or view. + /// + /// Name of the table. + /// SqlServerTableOrViewMetadata<TDbType>. + public new SqlServerTableOrViewMetadata GetTableOrView(SqlServerObjectName tableName) + { + return m_Tables.GetOrAdd(tableName, GetTableOrViewInternal); + } - /// - /// Preloads the scalar functions. - /// - public void PreloadScalarFunctions() - { - const string TvfSql = - @"SELECT + /// + /// Preloads the scalar functions. + /// + public void PreloadScalarFunctions() + { + const string TvfSql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId @@ -175,61 +174,61 @@ FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.type in ('FN')"; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new SqlCommand(TvfSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetScalarFunction(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetScalarFunction(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads the stored procedures. - /// - public void PreloadStoredProcedures() - { - const string StoredProcedureSql = - @"SELECT + /// + /// Preloads the stored procedures. + /// + public void PreloadStoredProcedures() + { + const string StoredProcedureSql = + @"SELECT s.name AS SchemaName, sp.name AS Name FROM SYS.procedures sp INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id;"; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(StoredProcedureSql, con)) { - con.Open(); - using (var cmd = new SqlCommand(StoredProcedureSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetStoredProcedure(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetStoredProcedure(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads the table value functions. - /// - public void PreloadTableFunctions() - { - const string TvfSql = - @"SELECT + /// + /// Preloads the table value functions. + /// + public void PreloadTableFunctions() + { + const string TvfSql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId @@ -237,140 +236,187 @@ FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.type in ('TF', 'IF', 'FT')"; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new SqlCommand(TvfSql, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetTableFunction(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetTableFunction(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads metadata for all tables. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadTables() - { - const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; + /// + /// Preloads metadata for all tables. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadTables() + { + const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(tableList, con)) { - con.Open(); - using (var cmd = new SqlCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetTableOrView(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetTableOrView(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads the user defined types. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadUserDefinedTableTypes() - { - const string tableList = @"SELECT s.name AS SchemaName, t.name AS Name FROM sys.types t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.is_user_defined = 1 AND t.is_table_type = 1;"; + /// + /// Preloads the user defined types. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadUserDefinedTableTypes() + { + const string tableList = @"SELECT s.name AS SchemaName, t.name AS Name FROM sys.types t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.is_user_defined = 1 AND t.is_table_type = 1;"; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(tableList, con)) { - con.Open(); - using (var cmd = new SqlCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetUserDefinedTableType(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetUserDefinedTableType(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Preloads metadata for all views. - /// - /// This is normally used only for testing. By default, metadata is loaded as needed. - public void PreloadViews() - { - const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.views t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; + /// + /// Preloads metadata for all views. + /// + /// This is normally used only for testing. By default, metadata is loaded as needed. + public void PreloadViews() + { + const string tableList = "SELECT t.name AS Name, s.name AS SchemaName FROM sys.views t INNER JOIN sys.schemas s ON t.schema_id=s.schema_id ORDER BY s.name, t.name"; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(tableList, con)) { - con.Open(); - using (var cmd = new SqlCommand(tableList, con)) + using (var reader = cmd.ExecuteReader()) { - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var schema = reader.GetString("SchemaName"); - var name = reader.GetString("Name"); - GetTableOrView(new SqlServerObjectName(schema, name)); - } + var schema = reader.GetString("SchemaName"); + var name = reader.GetString("Name"); + GetTableOrView(new SqlServerObjectName(schema, name)); } } } } + } - /// - /// Converts a value to a string suitable for use in a SQL statement. - /// - /// The value. - /// Optional database column type. - /// - public override string ValueToSqlValue(object value, SqlDbType? dbType) + /// + /// Converts a value to a string suitable for use in a SQL statement. + /// + /// The value. + /// Optional database column type. + /// + public override string ValueToSqlValue(object value, SqlDbType? dbType) + { + switch (value) { - switch (value) + case string s: + { + switch (dbType) + { + case SqlDbType.Char: + case SqlDbType.VarChar: + case SqlDbType.Text: + return "'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; + + case SqlDbType.NChar: + case SqlDbType.NVarChar: + case SqlDbType.NText: + return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; + + default: //Assume Unicode + return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; + } + } + + default: + return base.ValueToSqlValue(value, dbType); + } + } + + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This is designed to fail silently.")] + internal StoredProcedureMetadata? GetMasterStoredProcedure(SqlServerObjectName procedureName) + { + try + { + const string StoredProcedureSql = + @"SELECT + s.name AS SchemaName, + sp.name AS Name, + sp.object_id AS ObjectId + FROM SYS.procedures sp + INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id + WHERE s.name = @Schema AND sp.Name = @Name"; + + string actualSchema; + string actualName; + int objectId; + + using (var con = new SqlConnection(m_MasterConnectionBuilder.ConnectionString)) { - case string s: + con.Open(); + using (var cmd = new SqlCommand(StoredProcedureSql, con)) + { + cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? "dbo"); + cmd.Parameters.AddWithValue("@Name", procedureName.Name); + using (var reader = cmd.ExecuteReader()) { - switch (dbType) - { - case SqlDbType.Char: - case SqlDbType.VarChar: - case SqlDbType.Text: - return "'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; - - case SqlDbType.NChar: - case SqlDbType.NVarChar: - case SqlDbType.NText: - return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; - - default: //Assume Unicode - return "N'" + s.Replace("'", "''", StringComparison.OrdinalIgnoreCase) + "'"; - } + if (!reader.Read()) + return null; + + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); } + } + var objectName = new SqlServerObjectName(actualSchema, actualName); + var parameters = GetParameters(objectName.ToString(), objectId, con); - default: - return base.ValueToSqlValue(value, dbType); + return new StoredProcedureMetadata(objectName, parameters); } } - - internal ScalarFunctionMetadata GetScalarFunctionInternal(SqlServerObjectName scalarFunctionName) + catch { - const string sql = - @"SELECT s.name AS SchemaName, + return null; + } + } + + internal ScalarFunctionMetadata GetScalarFunctionInternal(SqlServerObjectName scalarFunctionName) + { + const string sql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId, COALESCE(t.name, t2.name) AS TypeName, @@ -379,62 +425,62 @@ internal ScalarFunctionMetadata GetScalarFunctio CONVERT(INT, COALESCE(p.precision, t.precision, t2.precision)) AS precision, CONVERT(INT, COALESCE(p.scale, t.scale, t2.scale)) AS scale - FROM sys.objects o - INNER JOIN sys.schemas s ON o.schema_id = s.schema_id - INNER JOIN sys.parameters p ON p.object_id = o.object_id AND p.parameter_id = 0 + FROM sys.objects o + INNER JOIN sys.schemas s ON o.schema_id = s.schema_id + INNER JOIN sys.parameters p ON p.object_id = o.object_id AND p.parameter_id = 0 LEFT JOIN sys.types t on p.system_type_id = t.user_type_id LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id - WHERE o.type IN ('FN') + WHERE o.type IN ('FN') AND s.name = @Schema AND o.name = @Name;"; - string actualSchema; - string actualName; - int objectId; + string actualSchema; + string actualName; + int objectId; - string fullTypeName; - string typeName; - bool isNullable; - int? maxLength; - int? precision; - int? scale; + string fullTypeName; + string typeName; + bool isNullable; + int? maxLength; + int? precision; + int? scale; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(sql, con)) { - con.Open(); - using (var cmd = new SqlCommand(sql, con)) + cmd.Parameters.AddWithValue("@Schema", scalarFunctionName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", scalarFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", scalarFunctionName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", scalarFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find scalar function {scalarFunctionName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - - typeName = reader.GetString("TypeName"); - isNullable = reader.GetBoolean("is_nullable"); - maxLength = reader.GetInt32OrNull("max_length"); - precision = reader.GetInt32OrNull("precision"); - scale = reader.GetInt32OrNull("scale"); - AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find scalar function {scalarFunctionName}"); + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); + + typeName = reader.GetString("TypeName"); + isNullable = reader.GetBoolean("is_nullable"); + maxLength = reader.GetInt32OrNull("max_length"); + precision = reader.GetInt32OrNull("precision"); + scale = reader.GetInt32OrNull("scale"); + AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); } + } - var objectName = new SqlServerObjectName(actualSchema, actualName); + var objectName = new SqlServerObjectName(actualSchema, actualName); - var parameters = GetParameters(objectName.ToString(), objectId, con); + var parameters = GetParameters(objectName.ToString(), objectId, con); - return new ScalarFunctionMetadata(objectName, parameters, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName); - } + return new ScalarFunctionMetadata(objectName, parameters, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName); } + } - internal StoredProcedureMetadata GetStoredProcedureInternal(SqlServerObjectName procedureName) - { - const string StoredProcedureSql = - @"SELECT + internal StoredProcedureMetadata GetStoredProcedureInternal(SqlServerObjectName procedureName) + { + const string StoredProcedureSql = + @"SELECT s.name AS SchemaName, sp.name AS Name, sp.object_id AS ObjectId @@ -442,6 +488,58 @@ FROM SYS.procedures sp INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id WHERE s.name = @Schema AND sp.Name = @Name"; + string actualSchema; + string actualName; + int objectId; + + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(StoredProcedureSql, con)) + { + cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", procedureName.Name); + using (var reader = cmd.ExecuteReader()) + { + if (!reader.Read()) + { + var sysStoredProcedure = GetSystemStoredProcedure(procedureName); + if (sysStoredProcedure != null) + return sysStoredProcedure; + + var masterStoredProcedure = GetMasterStoredProcedure(procedureName); + if (masterStoredProcedure != null) + return masterStoredProcedure; + + throw new MissingObjectException($"Could not find stored procedure {procedureName}"); + } + + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); + } + } + var objectName = new SqlServerObjectName(actualSchema, actualName); + var parameters = GetParameters(objectName.ToString(), objectId, con); + + return new StoredProcedureMetadata(objectName, parameters); + } + } + + [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This is designed to fail silently.")] + internal StoredProcedureMetadata? GetSystemStoredProcedure(SqlServerObjectName procedureName) + { + try + { + const string StoredProcedureSql = + @"SELECT + s.name AS SchemaName, + sp.name AS Name, + sp.object_id AS ObjectId + FROM SYS.all_objects sp + INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id + WHERE s.name = @Schema AND sp.Name = @Name"; + string actualSchema; string actualName; int objectId; @@ -451,22 +549,12 @@ FROM SYS.procedures sp con.Open(); using (var cmd = new SqlCommand(StoredProcedureSql, con)) { - cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? "sys"); cmd.Parameters.AddWithValue("@Name", procedureName.Name); using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) - { - var sysStoredProcedure = GetSystemStoredProcedure(procedureName); - if (sysStoredProcedure != null) - return sysStoredProcedure; - - var masterStoredProcedure = GetMasterStoredProcedure(procedureName); - if (masterStoredProcedure != null) - return masterStoredProcedure; - - throw new MissingObjectException($"Could not find stored procedure {procedureName}"); - } + return null; actualSchema = reader.GetString("SchemaName"); actualName = reader.GetString("Name"); @@ -474,110 +562,21 @@ FROM SYS.procedures sp } } var objectName = new SqlServerObjectName(actualSchema, actualName); - var parameters = GetParameters(objectName.ToString(), objectId, con); + var parameters = GetParameters(objectName.ToString(), objectId, con, useAllParameters: true); return new StoredProcedureMetadata(objectName, parameters); } } - - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This is designed to fail silently.")] - internal StoredProcedureMetadata? GetMasterStoredProcedure(SqlServerObjectName procedureName) + catch { - try - { - const string StoredProcedureSql = - @"SELECT - s.name AS SchemaName, - sp.name AS Name, - sp.object_id AS ObjectId - FROM SYS.procedures sp - INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id - WHERE s.name = @Schema AND sp.Name = @Name"; - - string actualSchema; - string actualName; - int objectId; - - using (var con = new SqlConnection(m_MasterConnectionBuilder.ConnectionString)) - { - con.Open(); - using (var cmd = new SqlCommand(StoredProcedureSql, con)) - { - cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? "dbo"); - cmd.Parameters.AddWithValue("@Name", procedureName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - return null; - - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - } - } - var objectName = new SqlServerObjectName(actualSchema, actualName); - var parameters = GetParameters(objectName.ToString(), objectId, con); - - return new StoredProcedureMetadata(objectName, parameters); - } - } - catch - { - return null; - } - } - - [SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "This is designed to fail silently.")] - internal StoredProcedureMetadata? GetSystemStoredProcedure(SqlServerObjectName procedureName) - { - try - { - const string StoredProcedureSql = - @"SELECT - s.name AS SchemaName, - sp.name AS Name, - sp.object_id AS ObjectId - FROM SYS.all_objects sp - INNER JOIN sys.schemas s ON sp.schema_id = s.schema_id - WHERE s.name = @Schema AND sp.Name = @Name"; - - string actualSchema; - string actualName; - int objectId; - - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); - using (var cmd = new SqlCommand(StoredProcedureSql, con)) - { - cmd.Parameters.AddWithValue("@Schema", procedureName.Schema ?? "sys"); - cmd.Parameters.AddWithValue("@Name", procedureName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - return null; - - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - } - } - var objectName = new SqlServerObjectName(actualSchema, actualName); - var parameters = GetParameters(objectName.ToString(), objectId, con, useAllParameters: true); - - return new StoredProcedureMetadata(objectName, parameters); - } - } - catch - { - return null; //this will silently fail - } + return null; //this will silently fail } + } - internal TableFunctionMetadata GetTableFunctionInternal(SqlServerObjectName tableFunctionName) - { - const string TvfSql = - @"SELECT + internal TableFunctionMetadata GetTableFunctionInternal(SqlServerObjectName tableFunctionName) + { + const string TvfSql = + @"SELECT s.name AS SchemaName, o.name AS Name, o.object_id AS ObjectId @@ -585,50 +584,50 @@ FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.type in ('TF', 'IF', 'FT') AND s.name = @Schema AND o.Name = @Name"; - /* - * TF = SQL table-valued-function - * IF = SQL inline table-valued function - * FT = Assembly (CLR) table-valued function - */ + /* + * TF = SQL table-valued-function + * IF = SQL inline table-valued function + * FT = Assembly (CLR) table-valued function + */ - string actualSchema; - string actualName; - int objectId; + string actualSchema; + string actualName; + int objectId; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(TvfSql, con)) { - con.Open(); - using (var cmd = new SqlCommand(TvfSql, con)) + cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableFunctionName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", tableFunctionName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find table valued function {tableFunctionName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find table valued function {tableFunctionName}"); + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); } - var objectName = new SqlServerObjectName(actualSchema, actualName); + } + var objectName = new SqlServerObjectName(actualSchema, actualName); - var columns = GetColumns(objectName.ToString(), objectId); - var parameters = GetParameters(objectName.ToString(), objectId, con); + var columns = GetColumns(objectName.ToString(), objectId); + var parameters = GetParameters(objectName.ToString(), objectId, con); - return new TableFunctionMetadata(objectName, parameters, columns); - } + return new TableFunctionMetadata(objectName, parameters, columns); } + } - internal SqlServerTableOrViewMetadata GetTableOrViewInternal(SqlServerObjectName tableName) - { - const string TableSql = - @"SELECT + internal SqlServerTableOrViewMetadata GetTableOrViewInternal(SqlServerObjectName tableName) + { + const string TableSql = + @"SELECT s.name AS SchemaName, t.name AS Name, t.object_id AS ObjectId, CONVERT(BIT, 1) AS IsTable, - (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers + (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers FROM SYS.tables t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE s.name = @Schema AND t.Name = @Name @@ -640,46 +639,46 @@ UNION ALL t.name AS Name, t.object_id AS ObjectId, CONVERT(BIT, 0) AS IsTable, - (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers + (SELECT COUNT(*) FROM sys.triggers t2 WHERE t2.parent_id = t.object_id) AS Triggers FROM SYS.views t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE s.name = @Schema AND t.Name = @Name"; - string actualSchema; - string actualName; - int objectId; - bool isTable; - bool hasTriggers; + string actualSchema; + string actualName; + int objectId; + bool isTable; + bool hasTriggers; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(TableSql, con)) { - con.Open(); - using (var cmd = new SqlCommand(TableSql, con)) + cmd.Parameters.AddWithValue("@Schema", tableName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", tableName.Name); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", tableName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find table or view {tableName}"); - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); - isTable = reader.GetBoolean("IsTable"); - hasTriggers = reader.GetInt32("Triggers") > 0; - } + if (!reader.Read()) + throw new MissingObjectException($"Could not find table or view {tableName}"); + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); + isTable = reader.GetBoolean("IsTable"); + hasTriggers = reader.GetInt32("Triggers") > 0; } } + } - var columns = GetColumns(tableName.ToString(), objectId); + var columns = GetColumns(tableName.ToString(), objectId); - return new SqlServerTableOrViewMetadata(this, new SqlServerObjectName(actualSchema, actualName), isTable, columns, hasTriggers); - } + return new SqlServerTableOrViewMetadata(this, new SqlServerObjectName(actualSchema, actualName), isTable, columns, hasTriggers); + } - internal UserDefinedTableTypeMetadata GetUserDefinedTableTypeInternal(SqlServerObjectName typeName) - { - const string sql = - @"SELECT s.name AS SchemaName, + internal UserDefinedTableTypeMetadata GetUserDefinedTableTypeInternal(SqlServerObjectName typeName) + { + const string sql = + @"SELECT s.name AS SchemaName, t.name AS Name, tt.type_table_object_id AS ObjectId FROM sys.types t @@ -688,9 +687,59 @@ FROM sys.types t LEFT JOIN sys.types t2 ON t.system_type_id = t2.user_type_id WHERE s.name = @Schema AND t.name = @Name AND t.is_table_type = 1;"; + string actualSchema; + string actualName; + int objectId; + + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(sql, con)) + { + cmd.Parameters.AddWithValue("@Schema", typeName.Schema ?? DefaultSchema); + cmd.Parameters.AddWithValue("@Name", typeName.Name); + using (var reader = cmd.ExecuteReader()) + { + if (!reader.Read()) + throw new MissingObjectException($"Could not find user defined type {typeName}"); + + actualSchema = reader.GetString("SchemaName"); + actualName = reader.GetString("Name"); + objectId = reader.GetInt32("ObjectId"); + } + } + } + + var columns = GetColumns(typeName.ToString(), objectId); + + return new UserDefinedTableTypeMetadata(new SqlServerObjectName(actualSchema, actualName), columns); + } + + /* + internal UserDefinedTypeMetadata GetUserDefinedTypeInternal(SqlServerObjectName typeName) + { + const string sql = + @"SELECT s.name AS SchemaName, + t.name AS Name, + t2.name AS BaseTypeName, + t.is_nullable, + CONVERT(INT, t.max_length) AS max_length, + CONVERT(INT, t.precision) AS precision, + CONVERT(INT, t.scale) AS scale +FROM sys.types t + INNER JOIN sys.schemas s ON t.schema_id = s.schema_id + LEFT JOIN sys.types t2 ON t.system_type_id = t2.user_type_id +WHERE s.name = @Schema AND t.name = @Name AND t.is_table_type = 0;"; + string actualSchema; string actualName; - int objectId; + string baseTypeName; + bool isTableType; + bool isNullable; + int? maxLength; + int? precision; + int? scale; + string fullTypeName; using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) { @@ -706,217 +755,167 @@ FROM sys.types t actualSchema = reader.GetString("SchemaName"); actualName = reader.GetString("Name"); - objectId = reader.GetInt32("ObjectId"); + baseTypeName = reader.GetString("BaseTypeName"); + + isNullable = reader.GetBoolean("is_nullable"); + maxLength = reader.GetInt32("max_length"); + precision = reader.GetInt32("precision"); + scale = reader.GetInt32("scale"); + + AdjustTypeDetails(baseTypeName, ref maxLength, ref precision, ref scale, out fullTypeName); } } } - var columns = GetColumns(typeName.ToString(), objectId); + var column = new ColumnMetadata(null, false, false, false, baseTypeName, SqlTypeNameToDbType(baseTypeName), null, isNullable, maxLength, precision, scale, fullTypeName, ToClrType(baseTypeName, isNullable, maxLength)); - return new UserDefinedTableTypeMetadata(new SqlServerObjectName(actualSchema, actualName), columns); - } - - /* - internal UserDefinedTypeMetadata GetUserDefinedTypeInternal(SqlServerObjectName typeName) - { - const string sql = - @"SELECT s.name AS SchemaName, - t.name AS Name, - t2.name AS BaseTypeName, - t.is_nullable, - CONVERT(INT, t.max_length) AS max_length, - CONVERT(INT, t.precision) AS precision, - CONVERT(INT, t.scale) AS scale -FROM sys.types t - INNER JOIN sys.schemas s ON t.schema_id = s.schema_id - LEFT JOIN sys.types t2 ON t.system_type_id = t2.user_type_id -WHERE s.name = @Schema AND t.name = @Name AND t.is_table_type = 0;"; + columns = new ColumnMetadataCollection(typeName.ToString(), new List>() { column }); - string actualSchema; - string actualName; - string baseTypeName; - bool isTableType; - bool isNullable; - int? maxLength; - int? precision; - int? scale; - string fullTypeName; - - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) - { - con.Open(); - using (var cmd = new SqlCommand(sql, con)) - { - cmd.Parameters.AddWithValue("@Schema", typeName.Schema ?? DefaultSchema); - cmd.Parameters.AddWithValue("@Name", typeName.Name); - using (var reader = cmd.ExecuteReader()) - { - if (!reader.Read()) - throw new MissingObjectException($"Could not find user defined type {typeName}"); - - actualSchema = reader.GetString("SchemaName"); - actualName = reader.GetString("Name"); - baseTypeName = reader.GetString("BaseTypeName"); - - isNullable = reader.GetBoolean("is_nullable"); - maxLength = reader.GetInt32("max_length"); - precision = reader.GetInt32("precision"); - scale = reader.GetInt32("scale"); - - AdjustTypeDetails(baseTypeName, ref maxLength, ref precision, ref scale, out fullTypeName); - } - } - } - - var column = new ColumnMetadata(null, false, false, false, baseTypeName, SqlTypeNameToDbType(baseTypeName), null, isNullable, maxLength, precision, scale, fullTypeName, ToClrType(baseTypeName, isNullable, maxLength)); - - columns = new ColumnMetadataCollection(typeName.ToString(), new List>() { column }); - - return new UserDefinedTableTypeMetadata(new SqlServerObjectName(actualSchema, actualName), isTableType, columns); - } - */ + return new UserDefinedTableTypeMetadata(new SqlServerObjectName(actualSchema, actualName), isTableType, columns); + } + */ - /// - /// Determines the database column type from the column type name. - /// - /// Name of the database column type. - /// NOT USED - /// - /// This does not honor registered types. This is only used for the database's hard-coded list of native types. - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - protected override SqlDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) + /// + /// Determines the database column type from the column type name. + /// + /// Name of the database column type. + /// NOT USED + /// + /// This does not honor registered types. This is only used for the database's hard-coded list of native types. + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + protected override SqlDbType? SqlTypeNameToDbType(string typeName, bool? isUnsigned = null) + { + switch (typeName) { - switch (typeName) - { - case "bigint": return SqlDbType.BigInt; - case "binary": return SqlDbType.Binary; - case "bit": return SqlDbType.Bit; - case "char": return SqlDbType.Char; - case "date": return SqlDbType.Date; - case "datetime": return SqlDbType.DateTime; - case "datetime2": return SqlDbType.DateTime2; - case "datetimeoffset": return SqlDbType.DateTimeOffset; - case "decimal": return SqlDbType.Decimal; - case "float": return SqlDbType.Float; - //case "geography": m_SqlDbType = SqlDbType.; - //case "geometry": m_SqlDbType = SqlDbType; - //case "hierarchyid": m_SqlDbType = SqlDbType.; - case "image": return SqlDbType.Image; - case "int": return SqlDbType.Int; - case "money": return SqlDbType.Money; - case "nchar": return SqlDbType.NChar; - case "ntext": return SqlDbType.NText; - case "numeric": return SqlDbType.Decimal; - case "nvarchar": return SqlDbType.NVarChar; - case "real": return SqlDbType.Real; - case "smalldatetime": return SqlDbType.SmallDateTime; - case "smallint": return SqlDbType.SmallInt; - case "smallmoney": return SqlDbType.SmallMoney; - case "sql_variant": return SqlDbType.Variant; - //case "sysname": m_SqlDbType = SqlDbType; - case "text": return SqlDbType.Text; - case "time": return SqlDbType.Time; - case "timestamp": return SqlDbType.Timestamp; - case "tinyint": return SqlDbType.TinyInt; - case "uniqueidentifier": return SqlDbType.UniqueIdentifier; - case "varbinary": return SqlDbType.VarBinary; - case "varchar": return SqlDbType.VarChar; - case "xml": return SqlDbType.Xml; - } - - return null; + case "bigint": return SqlDbType.BigInt; + case "binary": return SqlDbType.Binary; + case "bit": return SqlDbType.Bit; + case "char": return SqlDbType.Char; + case "date": return SqlDbType.Date; + case "datetime": return SqlDbType.DateTime; + case "datetime2": return SqlDbType.DateTime2; + case "datetimeoffset": return SqlDbType.DateTimeOffset; + case "decimal": return SqlDbType.Decimal; + case "float": return SqlDbType.Float; + //case "geography": m_SqlDbType = SqlDbType.; + //case "geometry": m_SqlDbType = SqlDbType; + //case "hierarchyid": m_SqlDbType = SqlDbType.; + case "image": return SqlDbType.Image; + case "int": return SqlDbType.Int; + case "money": return SqlDbType.Money; + case "nchar": return SqlDbType.NChar; + case "ntext": return SqlDbType.NText; + case "numeric": return SqlDbType.Decimal; + case "nvarchar": return SqlDbType.NVarChar; + case "real": return SqlDbType.Real; + case "smalldatetime": return SqlDbType.SmallDateTime; + case "smallint": return SqlDbType.SmallInt; + case "smallmoney": return SqlDbType.SmallMoney; + case "sql_variant": return SqlDbType.Variant; + //case "sysname": m_SqlDbType = SqlDbType; + case "text": return SqlDbType.Text; + case "time": return SqlDbType.Time; + case "timestamp": return SqlDbType.Timestamp; + case "tinyint": return SqlDbType.TinyInt; + case "uniqueidentifier": return SqlDbType.UniqueIdentifier; + case "varbinary": return SqlDbType.VarBinary; + case "varchar": return SqlDbType.VarChar; + case "xml": return SqlDbType.Xml; } - /// - /// Returns the CLR type that matches the indicated database column type. - /// - /// Type of the database column. - /// If nullable, Nullable versions of primitive types are returned. - /// Optional length. Used to distinguish between a char and string. Defaults to string. - /// - /// A CLR type or NULL if the type is unknown. - /// - /// This does not take into consideration registered types. - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - protected override Type? ToClrType(SqlDbType dbType, bool isNullable, int? maxLength) - { - switch (dbType) - { - case SqlDbType.BigInt: - return isNullable ? typeof(long?) : typeof(long); + return null; + } - case SqlDbType.Binary: - case SqlDbType.Image: - case SqlDbType.Timestamp: - case SqlDbType.VarBinary: - return typeof(byte[]); + /// + /// Returns the CLR type that matches the indicated database column type. + /// + /// Type of the database column. + /// If nullable, Nullable versions of primitive types are returned. + /// Optional length. Used to distinguish between a char and string. Defaults to string. + /// + /// A CLR type or NULL if the type is unknown. + /// + /// This does not take into consideration registered types. + [SuppressMessage("Microsoft.Maintainability", "CA1502")] + protected override Type? ToClrType(SqlDbType dbType, bool isNullable, int? maxLength) + { + switch (dbType) + { + case SqlDbType.BigInt: + return isNullable ? typeof(long?) : typeof(long); - case SqlDbType.Bit: - return isNullable ? typeof(bool?) : typeof(bool); + case SqlDbType.Binary: + case SqlDbType.Image: + case SqlDbType.Timestamp: + case SqlDbType.VarBinary: + return typeof(byte[]); - case SqlDbType.Char: - case SqlDbType.NChar: - case SqlDbType.NVarChar: - case SqlDbType.VarChar: - return (maxLength == 1) ? - (isNullable ? typeof(char?) : typeof(char)) - : typeof(string); + case SqlDbType.Bit: + return isNullable ? typeof(bool?) : typeof(bool); - case SqlDbType.DateTime: - case SqlDbType.Date: - case SqlDbType.DateTime2: - case SqlDbType.SmallDateTime: - return isNullable ? typeof(DateTime?) : typeof(DateTime); + case SqlDbType.Char: + case SqlDbType.NChar: + case SqlDbType.NVarChar: + case SqlDbType.VarChar: + return (maxLength == 1) ? + (isNullable ? typeof(char?) : typeof(char)) + : typeof(string); - case SqlDbType.Decimal: - case SqlDbType.Money: - case SqlDbType.SmallMoney: - return isNullable ? typeof(decimal?) : typeof(decimal); + case SqlDbType.DateTime: + case SqlDbType.Date: + case SqlDbType.DateTime2: + case SqlDbType.SmallDateTime: + return isNullable ? typeof(DateTime?) : typeof(DateTime); - case SqlDbType.Float: - return isNullable ? typeof(double?) : typeof(double); + case SqlDbType.Decimal: + case SqlDbType.Money: + case SqlDbType.SmallMoney: + return isNullable ? typeof(decimal?) : typeof(decimal); - case SqlDbType.Int: - return isNullable ? typeof(int?) : typeof(int); + case SqlDbType.Float: + return isNullable ? typeof(double?) : typeof(double); - case SqlDbType.NText: - case SqlDbType.Text: - case SqlDbType.Xml: - return typeof(string); + case SqlDbType.Int: + return isNullable ? typeof(int?) : typeof(int); - case SqlDbType.Real: - return isNullable ? typeof(float?) : typeof(float); + case SqlDbType.NText: + case SqlDbType.Text: + case SqlDbType.Xml: + return typeof(string); - case SqlDbType.UniqueIdentifier: - return isNullable ? typeof(Guid?) : typeof(Guid); + case SqlDbType.Real: + return isNullable ? typeof(float?) : typeof(float); - case SqlDbType.SmallInt: - return isNullable ? typeof(short?) : typeof(short); + case SqlDbType.UniqueIdentifier: + return isNullable ? typeof(Guid?) : typeof(Guid); - case SqlDbType.TinyInt: - return isNullable ? typeof(byte?) : typeof(byte); + case SqlDbType.SmallInt: + return isNullable ? typeof(short?) : typeof(short); - case SqlDbType.Variant: - return typeof(object); + case SqlDbType.TinyInt: + return isNullable ? typeof(byte?) : typeof(byte); - case SqlDbType.Time: - return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); + case SqlDbType.Variant: + return typeof(object); - case SqlDbType.DateTimeOffset: - return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); + case SqlDbType.Time: + return isNullable ? typeof(TimeSpan?) : typeof(TimeSpan); - case SqlDbType.Udt: - case SqlDbType.Structured: - return null; - } + case SqlDbType.DateTimeOffset: + return isNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); - return null; + case SqlDbType.Udt: + case SqlDbType.Structured: + return null; } - ColumnMetadataCollection GetColumns(string ownerName, int objectId) - { - const string ColumnSql = - @"WITH PKS + return null; + } + + ColumnMetadataCollection GetColumns(string ownerName, int objectId) + { + const string ColumnSql = + @"WITH PKS AS ( SELECT c.name , 1 AS is_primary_key FROM sys.indexes i @@ -935,190 +934,189 @@ FROM sys.indexes i Convert(bit, ISNULL(PKS.is_primary_key, 0)) AS is_primary_key, COALESCE(t.name, t2.name) AS TypeName, c.is_nullable, - CONVERT(INT, COALESCE(c.max_length, t.max_length, t2.max_length)) AS max_length, - CONVERT(INT, COALESCE(c.precision, t.precision, t2.precision)) AS precision, - CONVERT(INT, COALESCE(c.scale, t.scale, t2.scale)) AS scale + CONVERT(INT, COALESCE(c.max_length, t.max_length, t2.max_length)) AS max_length, + CONVERT(INT, COALESCE(c.precision, t.precision, t2.precision)) AS precision, + CONVERT(INT, COALESCE(c.scale, t.scale, t2.scale)) AS scale FROM sys.columns c LEFT JOIN PKS ON c.name = PKS.name LEFT JOIN sys.types t on c.system_type_id = t.user_type_id LEFT JOIN sys.types t2 ON c.user_type_id = t2.user_type_id - WHERE object_id = @ObjectId;"; + WHERE object_id = @ObjectId;"; - var columns = new List>(); - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + var columns = new List>(); + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + using (var cmd = new SqlCommand(ColumnSql, con)) { - con.Open(); - using (var cmd = new SqlCommand(ColumnSql, con)) + cmd.Parameters.AddWithValue("@ObjectId", objectId); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@ObjectId", objectId); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var name = reader.GetString("ColumnName"); - var computed = reader.GetBoolean("is_computed"); - var primary = reader.GetBoolean("is_primary_key"); - var isIdentity = reader.GetBoolean("is_identity"); - var typeName = reader.GetString("TypeName"); - var isNullable = reader.GetBoolean("is_nullable"); - int? maxLength = reader.GetInt32OrNull("max_length"); - int? precision = reader.GetInt32OrNull("precision"); - int? scale = reader.GetInt32OrNull("scale"); - string fullTypeName; - AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); - - columns.Add(new ColumnMetadata(name, computed, primary, isIdentity, typeName, SqlTypeNameToDbType(typeName), "[" + name + "]", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, maxLength))); - } + var name = reader.GetString("ColumnName"); + var computed = reader.GetBoolean("is_computed"); + var primary = reader.GetBoolean("is_primary_key"); + var isIdentity = reader.GetBoolean("is_identity"); + var typeName = reader.GetString("TypeName"); + var isNullable = reader.GetBoolean("is_nullable"); + int? maxLength = reader.GetInt32OrNull("max_length"); + int? precision = reader.GetInt32OrNull("precision"); + int? scale = reader.GetInt32OrNull("scale"); + string fullTypeName; + AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); + + columns.Add(new ColumnMetadata(name, computed, primary, isIdentity, typeName, SqlTypeNameToDbType(typeName), "[" + name + "]", isNullable, maxLength, precision, scale, fullTypeName, ToClrType(typeName, isNullable, maxLength))); } } } - return new ColumnMetadataCollection(ownerName, columns); } + return new ColumnMetadataCollection(ownerName, columns); + } - List GetColumnsForIndex(SqlServerObjectName tableName) - { - const string columnSql = @"SELECT c.name, - ic.is_descending_key, - ic.is_included_column, - ic.index_id + List GetColumnsForIndex(SqlServerObjectName tableName) + { + const string columnSql = @"SELECT c.name, + ic.is_descending_key, + ic.is_included_column, + ic.index_id FROM sys.index_columns ic - INNER JOIN sys.objects o - ON ic.object_id = o.object_id - INNER JOIN sys.schemas s - ON o.schema_id = s.schema_id - INNER JOIN sys.columns c - ON ic.object_id = c.object_id - AND ic.column_id = c.column_id + INNER JOIN sys.objects o + ON ic.object_id = o.object_id + INNER JOIN sys.schemas s + ON o.schema_id = s.schema_id + INNER JOIN sys.columns c + ON ic.object_id = c.object_id + AND ic.column_id = c.column_id WHERE o.name = @Name - AND s.name = @Schema + AND s.name = @Schema ORDER BY ic.key_ordinal;"; - var tableColumns = GetTableOrView(tableName).Columns; + var tableColumns = GetTableOrView(tableName).Columns; - using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + { + con.Open(); + + using (var cmd = new SqlCommand(columnSql, con)) { - con.Open(); + cmd.Parameters.AddWithValue("@Schema", tableName.Schema); + cmd.Parameters.AddWithValue("@Name", tableName.Name); - using (var cmd = new SqlCommand(columnSql, con)) + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@Schema", tableName.Schema); - cmd.Parameters.AddWithValue("@Name", tableName.Name); + var results = new List(); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - var results = new List(); + var is_included_column = reader.GetBoolean("is_included_column"); + var is_descending_key = reader.GetBooleanOrNull("is_descending_key"); + var name = reader.GetString("Name"); + var index_id = reader.GetInt32("index_id"); + var column = tableColumns[name]; - while (reader.Read()) - { - var is_included_column = reader.GetBoolean("is_included_column"); - var is_descending_key = reader.GetBooleanOrNull("is_descending_key"); - var name = reader.GetString("Name"); - var index_id = reader.GetInt32("index_id"); - var column = tableColumns[name]; - - results.Add(new SqlServerIndexColumnMetadata(column, is_descending_key, is_included_column, index_id)); - } - return results; + results.Add(new SqlServerIndexColumnMetadata(column, is_descending_key, is_included_column, index_id)); } + return results; } } } + } - //ParameterMetadataCollection GetParameters(string procedureName, int objectId) - //{ - // using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) - // { - // con.Open(); - // return GetParameters(procedureName, objectId, con); - // } - //} + //ParameterMetadataCollection GetParameters(string procedureName, int objectId) + //{ + // using (var con = new SqlConnection(m_ConnectionBuilder.ConnectionString)) + // { + // con.Open(); + // return GetParameters(procedureName, objectId, con); + // } + //} - ParameterMetadataCollection GetParameters(string procedureName, int objectId, SqlConnection con, bool useAllParameters = false) + ParameterMetadataCollection GetParameters(string procedureName, int objectId, SqlConnection con, bool useAllParameters = false) + { + try { - try - { - const string ParameterSqlA = - @"SELECT p.name AS ParameterName , - COALESCE(t.name, t2.name) AS TypeName, + const string ParameterSqlA = + @"SELECT p.name AS ParameterName , + COALESCE(t.name, t2.name) AS TypeName, COALESCE(t.is_nullable, t2.is_nullable) as is_nullable, - CONVERT(INT, t.max_length) AS max_length, - CONVERT(INT, t.precision) AS precision, - CONVERT(INT, t.scale) AS scale, - p.is_output - FROM sys.parameters p - LEFT JOIN sys.types t ON p.system_type_id = t.user_type_id - LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id - WHERE p.object_id = @ObjectId AND p.parameter_id <> 0 - ORDER BY p.parameter_id;"; - - const string ParameterSqlB = - @"SELECT p.name AS ParameterName , - COALESCE(t.name, t2.name) AS TypeName, + CONVERT(INT, t.max_length) AS max_length, + CONVERT(INT, t.precision) AS precision, + CONVERT(INT, t.scale) AS scale, + p.is_output + FROM sys.parameters p + LEFT JOIN sys.types t ON p.system_type_id = t.user_type_id + LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id + WHERE p.object_id = @ObjectId AND p.parameter_id <> 0 + ORDER BY p.parameter_id;"; + + const string ParameterSqlB = + @"SELECT p.name AS ParameterName , + COALESCE(t.name, t2.name) AS TypeName, COALESCE(t.is_nullable, t2.is_nullable) as is_nullable, - CONVERT(INT, t.max_length) AS max_length, - CONVERT(INT, t.precision) AS precision, - CONVERT(INT, t.scale) AS scale, - p.is_output - FROM sys.all_parameters p - LEFT JOIN sys.types t ON p.system_type_id = t.user_type_id - LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id - WHERE p.object_id = @ObjectId AND p.parameter_id <> 0 - ORDER BY p.parameter_id;"; + CONVERT(INT, t.max_length) AS max_length, + CONVERT(INT, t.precision) AS precision, + CONVERT(INT, t.scale) AS scale, + p.is_output + FROM sys.all_parameters p + LEFT JOIN sys.types t ON p.system_type_id = t.user_type_id + LEFT JOIN sys.types t2 ON p.user_type_id = t2.user_type_id + WHERE p.object_id = @ObjectId AND p.parameter_id <> 0 + ORDER BY p.parameter_id;"; - //we exclude parameter_id 0 because it is the return type of scalar functions. - //we need to use all_parameters for system stored procedures + //we exclude parameter_id 0 because it is the return type of scalar functions. + //we need to use all_parameters for system stored procedures - var ParameterSql = !useAllParameters ? ParameterSqlA : ParameterSqlB; + var ParameterSql = !useAllParameters ? ParameterSqlA : ParameterSqlB; - var parameters = new List>(); + var parameters = new List>(); - using (var cmd = new SqlCommand(ParameterSql, con)) + using (var cmd = new SqlCommand(ParameterSql, con)) + { + cmd.Parameters.AddWithValue("@ObjectId", objectId); + using (var reader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("@ObjectId", objectId); - using (var reader = cmd.ExecuteReader()) + while (reader.Read()) { - while (reader.Read()) - { - var name = reader.GetString("ParameterName"); - var typeName = reader.GetString("TypeName"); - const bool isNullable = true; - var maxLength = reader.GetInt32OrNull("max_length"); - var precision = reader.GetInt32OrNull("precision"); - var scale = reader.GetInt32OrNull("scale"); - var isOutput = reader.GetBoolean("is_output"); - string fullTypeName; - AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); - - var direction = isOutput ? ParameterDirection.Output : ParameterDirection.Input; - - parameters.Add(new ParameterMetadata(name, name, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName, direction)); - } + var name = reader.GetString("ParameterName"); + var typeName = reader.GetString("TypeName"); + const bool isNullable = true; + var maxLength = reader.GetInt32OrNull("max_length"); + var precision = reader.GetInt32OrNull("precision"); + var scale = reader.GetInt32OrNull("scale"); + var isOutput = reader.GetBoolean("is_output"); + string fullTypeName; + AdjustTypeDetails(typeName, ref maxLength, ref precision, ref scale, out fullTypeName); + + var direction = isOutput ? ParameterDirection.Output : ParameterDirection.Input; + + parameters.Add(new ParameterMetadata(name, name, typeName, SqlTypeNameToDbType(typeName), isNullable, maxLength, precision, scale, fullTypeName, direction)); } } - - return new ParameterMetadataCollection(procedureName, parameters); } - catch (Exception ex) - { - throw new MetadataException($"Error getting parameters for {procedureName}", ex); - } - } - class SqlServerIndexColumnMetadata : IndexColumnMetadata + return new ParameterMetadataCollection(procedureName, parameters); + } + catch (Exception ex) { - /// - /// Initializes a new instance of the IndexColumnMetadata class. - /// - /// The underlying column details. - /// Indicates the column is indexed in descending order. - /// Indicates the column is an unindexed, included column. - /// - internal SqlServerIndexColumnMetadata(ColumnMetadata column, bool? isDescending, bool isIncluded, int indexId) : base(column, isDescending, isIncluded) - { - IndexId = indexId; - } + throw new MetadataException($"Error getting parameters for {procedureName}", ex); + } + } - internal int IndexId { get; } + class SqlServerIndexColumnMetadata : IndexColumnMetadata + { + /// + /// Initializes a new instance of the IndexColumnMetadata class. + /// + /// The underlying column details. + /// Indicates the column is indexed in descending order. + /// Indicates the column is an unindexed, included column. + /// + internal SqlServerIndexColumnMetadata(ColumnMetadata column, bool? isDescending, bool isIncluded, int indexId) : base(column, isDescending, isIncluded) + { + IndexId = indexId; } + + internal int IndexId { get; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerObjectName.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerObjectName.cs index 946f0c310..6e8a10ac8 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerObjectName.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerObjectName.cs @@ -1,218 +1,217 @@ using System.Diagnostics.CodeAnalysis; using Tortuga.Anchor; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Represents an object in SQL Server (e.g. table, view, procedure) +/// +public struct SqlServerObjectName : IEquatable { /// - /// Represents an object in SQL Server (e.g. table, view, procedure) + /// An empty schema/name pair + /// + public static readonly SqlServerObjectName Empty; + + /// + /// Initializes a new instance of the struct. + /// + /// The schema. + /// The name. + public SqlServerObjectName(string? schema, string name) + : this(null, schema, name) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The database. + /// The schema. + /// The name. + public SqlServerObjectName(string? database, string? schema, string name) + { + Database = Normalize(database); + Schema = Normalize(schema); + Name = Normalize(name); + } + + /// + /// Initializes a new instance of the struct. /// - public struct SqlServerObjectName : IEquatable + /// Name of the schema and. + public SqlServerObjectName(string schemaAndName) { - /// - /// An empty schema/name pair - /// - public static readonly SqlServerObjectName Empty; - - /// - /// Initializes a new instance of the struct. - /// - /// The schema. - /// The name. - public SqlServerObjectName(string? schema, string name) - : this(null, schema, name) + if (string.IsNullOrEmpty(schemaAndName)) + throw new ArgumentException($"{nameof(schemaAndName)} is null or empty.", nameof(schemaAndName)); + + var parts = schemaAndName.Split(new[] { '.' }, 2); + if (parts.Length == 1) { + Database = null; + Schema = null; + Name = Normalize(parts[0]); } - - /// - /// Initializes a new instance of the struct. - /// - /// The database. - /// The schema. - /// The name. - public SqlServerObjectName(string? database, string? schema, string name) + else if (parts.Length == 2) { - Database = Normalize(database); - Schema = Normalize(schema); - Name = Normalize(name); + Database = null; + Schema = Normalize(parts[0]); + Name = Normalize(parts[1]); } - - /// - /// Initializes a new instance of the struct. - /// - /// Name of the schema and. - public SqlServerObjectName(string schemaAndName) + else if (parts.Length == 3) { - if (string.IsNullOrEmpty(schemaAndName)) - throw new ArgumentException($"{nameof(schemaAndName)} is null or empty.", nameof(schemaAndName)); - - var parts = schemaAndName.Split(new[] { '.' }, 2); - if (parts.Length == 1) - { - Database = null; - Schema = null; - Name = Normalize(parts[0]); - } - else if (parts.Length == 2) - { - Database = null; - Schema = Normalize(parts[0]); - Name = Normalize(parts[1]); - } - else if (parts.Length == 3) - { - Database = Normalize(parts[1]); - Schema = Normalize(parts[1]); - Name = Normalize(parts[2]); - } - else - { - throw new ArgumentException("Four-part identifiers are not supported."); - } + Database = Normalize(parts[1]); + Schema = Normalize(parts[1]); + Name = Normalize(parts[2]); } + else + { + throw new ArgumentException("Four-part identifiers are not supported."); + } + } - /// - /// Gets the database. - /// - /// The database. - public string? Database { get; } - - /// - /// Gets the name. - /// - /// - /// The name. - /// - public string Name { get; } - - /// - /// Gets the schema. - /// - /// - /// The schema. - /// - public string? Schema { get; } + /// + /// Gets the database. + /// + /// The database. + public string? Database { get; } + + /// + /// Gets the name. + /// + /// + /// The name. + /// + public string Name { get; } + + /// + /// Gets the schema. + /// + /// + /// The schema. + /// + public string? Schema { get; } #pragma warning disable CA2225 // Operator overloads have named alternates - /// - /// Perform an implicit conversion from to . - /// - /// The value. - /// - /// The result of the conversion. - /// - public static implicit operator SqlServerObjectName(string value) + /// + /// Perform an implicit conversion from to . + /// + /// The value. + /// + /// The result of the conversion. + /// + public static implicit operator SqlServerObjectName(string value) #pragma warning restore CA2225 // Operator overloads have named alternates - { - return new SqlServerObjectName(value); - } + { + return new SqlServerObjectName(value); + } - /// - /// Implements the operator !=. - /// - /// The left value. - /// The right value. - /// - /// The result of the operator. - /// - /// This is a case-insensitive comparison. - public static bool operator !=(SqlServerObjectName left, SqlServerObjectName right) - { - return !(left == right); - } + /// + /// Implements the operator !=. + /// + /// The left value. + /// The right value. + /// + /// The result of the operator. + /// + /// This is a case-insensitive comparison. + public static bool operator !=(SqlServerObjectName left, SqlServerObjectName right) + { + return !(left == right); + } - /// - /// Implements the operator ==. - /// - /// The left value. - /// The right value. - /// - /// The result of the operator. - /// - /// This is a case-insensitive comparison. - public static bool operator ==(SqlServerObjectName left, SqlServerObjectName right) - { - return string.Equals(left.Database, right.Database, StringComparison.OrdinalIgnoreCase) - && string.Equals(left.Schema, right.Schema, StringComparison.OrdinalIgnoreCase) - && string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); - } + /// + /// Implements the operator ==. + /// + /// The left value. + /// The right value. + /// + /// The result of the operator. + /// + /// This is a case-insensitive comparison. + public static bool operator ==(SqlServerObjectName left, SqlServerObjectName right) + { + return string.Equals(left.Database, right.Database, StringComparison.OrdinalIgnoreCase) + && string.Equals(left.Schema, right.Schema, StringComparison.OrdinalIgnoreCase) + && string.Equals(left.Name, right.Name, StringComparison.OrdinalIgnoreCase); + } - /// - /// Determines whether the specified , is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - /// This is a case-insensitive comparison. - public override bool Equals(object? obj) - { - var other = obj as SqlServerObjectName?; - if (other == null) - return false; - return this == other; - } + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + /// This is a case-insensitive comparison. + public override bool Equals(object? obj) + { + var other = obj as SqlServerObjectName?; + if (other == null) + return false; + return this == other; + } - /// - /// Returns true if the two objects are equal. - /// - /// - /// - /// This is a case-insensitive comparison. - public bool Equals(SqlServerObjectName other) - { - return this == other; - } + /// + /// Returns true if the two objects are equal. + /// + /// + /// + /// This is a case-insensitive comparison. + public bool Equals(SqlServerObjectName other) + { + return this == other; + } - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - /// This is a case-insensitive comparison. - public override int GetHashCode() - { - return Name.GetHashCode(StringComparison.OrdinalIgnoreCase); - } + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + /// This is a case-insensitive comparison. + public override int GetHashCode() + { + return Name.GetHashCode(StringComparison.OrdinalIgnoreCase); + } - /// - /// To the quoted string. - /// - /// - public string ToQuotedString() - { - if (Schema == null) - return $"[{Name}]"; - else if (Database == null) - return $"[{Schema}].[{Name}]"; - else - return $"[{Database}].[{Schema}].[{Name}]"; - } + /// + /// To the quoted string. + /// + /// + public string ToQuotedString() + { + if (Schema == null) + return $"[{Name}]"; + else if (Database == null) + return $"[{Schema}].[{Name}]"; + else + return $"[{Database}].[{Schema}].[{Name}]"; + } - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - if (Schema == null) - return $"{Name}"; - else if (Database == null) - return $"{Schema}.{Name}"; - else - return $"{Database}.{Schema}.{Name}"; - } + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + if (Schema == null) + return $"{Name}"; + else if (Database == null) + return $"{Schema}.{Name}"; + else + return $"{Database}.{Schema}.{Name}"; + } - [return: NotNullIfNotNull("value")] - private static string? Normalize(string? value) - { - if (value.IsNullOrWhiteSpace()) - return null; + [return: NotNullIfNotNull("value")] + private static string? Normalize(string? value) + { + if (value.IsNullOrWhiteSpace()) + return null; - return value.Replace("[", "", StringComparison.Ordinal).Replace("]", "", StringComparison.Ordinal); - } + return value.Replace("[", "", StringComparison.Ordinal).Replace("]", "", StringComparison.Ordinal); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOpenDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOpenDataSource.cs index 6232897a1..c0b1388e0 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOpenDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOpenDataSource.cs @@ -2,203 +2,199 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerOpenDataSource. +/// +[UseTrait(typeof(Traits.OpenDataSourceTrait))] +public partial class SqlServerOpenDataSource : SqlServerDataSourceBase { + internal SqlServerOpenDataSource(SqlServerDataSource dataSource, SqlConnection connection, SqlTransaction? transaction) : base(new SqlServerDataSourceSettings(dataSource)) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + + m_BaseDataSource = dataSource; + m_Connection = connection; + m_Transaction = transaction; + } + /// - /// Class SqlServerOpenDataSource. + /// Executes the specified operation. /// - [UseTrait(typeof(Traits.OpenDataSourceTrait))] - public partial class SqlServerOpenDataSource : SqlServerDataSourceBase + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + /// + /// executionToken;executionToken is null. + /// or + /// implementation;implementation is null. + /// + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) { - internal SqlServerOpenDataSource(SqlServerDataSource dataSource, SqlConnection connection, SqlTransaction? transaction) : base(new SqlServerDataSourceSettings(dataSource)) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - m_BaseDataSource = dataSource; - m_Connection = connection; - m_Transaction = transaction; - } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - /// - /// executionToken;executionToken is null. - /// or - /// implementation;implementation is null. - /// - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + using (var cmd = new SqlCommand()) + { + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); - try - { - using (var cmd = new SqlCommand()) - { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + CommandFixup(executionToken, cmd); + + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + /// + /// Executes the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + /// + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - try + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try + { + using (var cmd = new SqlCommand()) { - var rows = implementation(m_Connection, m_Transaction); + cmd.Connection = m_Connection; + if (m_Transaction != null) + cmd.Transaction = m_Transaction; + + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + CommandFixup(executionToken, cmd); + + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } } - - /// - /// Executes the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - /// - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var cmd = new SqlCommand()) - { - cmd.Connection = m_Connection; - if (m_Transaction != null) - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - private partial SqlServerOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) - { - if (userValue != null) - UserValue = userValue; - if (additionalRules != null) - AuditRules = new AuditRuleCollection(AuditRules, additionalRules); + private partial SqlServerOpenDataSource OnOverride(IEnumerable? additionalRules, object? userValue) + { + if (userValue != null) + UserValue = userValue; + if (additionalRules != null) + AuditRules = new AuditRuleCollection(AuditRules, additionalRules); - return this; - } + return this; } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOperationExecutionToken.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOperationExecutionToken.cs index f628cf244..92be31d2f 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOperationExecutionToken.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerOperationExecutionToken.cs @@ -1,22 +1,20 @@ using Tortuga.Chain.Core; using Tortuga.Chain.DataSources; +namespace Tortuga.Chain.SqlServer; -namespace Tortuga.Chain.SqlServer +/// +/// Class SqlServerOperationExecutionToken. +/// +/// +public class SqlServerOperationExecutionToken : OperationExecutionToken { /// - /// Class SqlServerOperationExecutionToken. + /// Initializes a new instance of the class. /// - /// - public class SqlServerOperationExecutionToken : OperationExecutionToken + /// The data source. + /// Name of the operation. This is used for logging. + public SqlServerOperationExecutionToken(IOperationDataSource dataSource, string operationName) : base(dataSource, operationName) { - /// - /// Initializes a new instance of the class. - /// - /// The data source. - /// Name of the operation. This is used for logging. - public SqlServerOperationExecutionToken(IOperationDataSource dataSource, string operationName) : base(dataSource, operationName) - { - } } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTableOrViewMetadata.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTableOrViewMetadata.cs index 9af9b7944..1c290abc0 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTableOrViewMetadata.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTableOrViewMetadata.cs @@ -1,32 +1,32 @@ using Tortuga.Chain.Metadata; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerTableOrViewMetadata. +/// +/// The type of the t database type. +/// +public class SqlServerTableOrViewMetadata : TableOrViewMetadata + where TDbType : struct { /// - /// Class SqlServerTableOrViewMetadata. + /// Initializes a new instance of the class. /// - /// The type of the t database type. - /// - public class SqlServerTableOrViewMetadata : TableOrViewMetadata where TDbType : struct + /// The metadata cache. + /// The name. + /// if set to true is a table. + /// The columns. + /// if set to true has triggers. + public SqlServerTableOrViewMetadata(DatabaseMetadataCache metadataCache, SqlServerObjectName name, bool isTable, ColumnMetadataCollection columns, bool hasTriggers) : base(metadataCache, name, isTable, columns) { - /// - /// Initializes a new instance of the class. - /// - /// The metadata cache. - /// The name. - /// if set to true is a table. - /// The columns. - /// if set to true has triggers. - public SqlServerTableOrViewMetadata(DatabaseMetadataCache metadataCache, SqlServerObjectName name, bool isTable, ColumnMetadataCollection columns, bool hasTriggers) : base(metadataCache, name, isTable, columns) - { - HasTriggers = hasTriggers; - } - - /// - /// Gets a value indicating whether the associated table has triggers. - /// - /// true if this instance has triggers; otherwise, false. - /// This affects SQL generation. - public bool HasTriggers { get; } + HasTriggers = hasTriggers; } -} + + /// + /// Gets a value indicating whether the associated table has triggers. + /// + /// true if this instance has triggers; otherwise, false. + /// This affects SQL generation. + public bool HasTriggers { get; } +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTransactionalDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTransactionalDataSource.cs index 5acccbca5..91a0c33f6 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTransactionalDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/SqlServerTransactionalDataSource.cs @@ -1,244 +1,235 @@ using Tortuga.Chain.Core; using Tortuga.Shipwright; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +/// +/// Class SqlServerTransactionalDataSource. +/// +[UseTrait(typeof(Traits.TransactionalDataSourceTrait))] +public partial class SqlServerTransactionalDataSource : SqlServerDataSourceBase { /// - /// Class SqlServerTransactionalDataSource. + /// Initializes a new instance of the class. /// - [UseTrait(typeof(Traits.TransactionalDataSourceTrait))] - public partial class SqlServerTransactionalDataSource : SqlServerDataSourceBase + /// The parent connection. + /// Name of the transaction. + /// The isolation level. If not supplied, will use the database default. + /// If true, logging events are forwarded to the parent connection. + public SqlServerTransactionalDataSource(SqlServerDataSource dataSource, string? transactionName, IsolationLevel? isolationLevel, bool forwardEvents) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) { + Name = dataSource.Name; - /// - /// Initializes a new instance of the class. - /// - /// The parent connection. - /// Name of the transaction. - /// The isolation level. If not supplied, will use the database default. - /// If true, logging events are forwarded to the parent connection. - public SqlServerTransactionalDataSource(SqlServerDataSource dataSource, string? transactionName, IsolationLevel? isolationLevel, bool forwardEvents) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) - { - Name = dataSource.Name; + m_BaseDataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); + m_Connection = dataSource.CreateConnection(); + TransactionName = transactionName; - m_BaseDataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource), $"{nameof(dataSource)} is null."); - m_Connection = dataSource.CreateConnection(); - TransactionName = transactionName; + if (isolationLevel == null) + m_Transaction = m_Connection.BeginTransaction(transactionName); + else + m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value, transactionName); - if (isolationLevel == null) - m_Transaction = m_Connection.BeginTransaction(transactionName); - else - m_Transaction = m_Connection.BeginTransaction(isolationLevel.Value, transactionName); - - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } - /// - /// Initializes a new instance of the class. - /// - /// The parent connection. - /// Name of the transaction. - /// If true, logging events are forwarded to the parent connection. - /// The connection. - /// The transaction. - internal SqlServerTransactionalDataSource(SqlServerDataSource dataSource, string? transactionName, bool forwardEvents, SqlConnection connection, SqlTransaction transaction) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) - { - Name = dataSource.Name; + /// + /// Initializes a new instance of the class. + /// + /// The parent connection. + /// Name of the transaction. + /// If true, logging events are forwarded to the parent connection. + /// The connection. + /// The transaction. + internal SqlServerTransactionalDataSource(SqlServerDataSource dataSource, string? transactionName, bool forwardEvents, SqlConnection connection, SqlTransaction transaction) : base(new SqlServerDataSourceSettings(dataSource, forwardEvents)) + { + Name = dataSource.Name; - m_BaseDataSource = dataSource; - m_Connection = connection; - TransactionName = transactionName; - m_Transaction = transaction; + m_BaseDataSource = dataSource; + m_Connection = connection; + TransactionName = transactionName; + m_Transaction = transaction; - if (forwardEvents) - { - ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); - ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); - ExecutionError += (sender, e) => dataSource.OnExecutionError(e); - ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); - } - AuditRules = dataSource.AuditRules; - UserValue = dataSource.UserValue; + if (forwardEvents) + { + ExecutionStarted += (sender, e) => dataSource.OnExecutionStarted(e); + ExecutionFinished += (sender, e) => dataSource.OnExecutionFinished(e); + ExecutionError += (sender, e) => dataSource.OnExecutionError(e); + ExecutionCanceled += (sender, e) => dataSource.OnExecutionCanceled(e); } + AuditRules = dataSource.AuditRules; + UserValue = dataSource.UserValue; + } + /// + /// Gets the name of the transaction. + /// + /// The name of the transaction. + public string? TransactionName { get; } + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - /// - /// Gets the name of the transaction. - /// - /// The name of the transaction. - public string? TransactionName { get; } + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + using (var cmd = new SqlCommand()) + { + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + CommandFixup(executionToken, cmd); - try - { - using (var cmd = new SqlCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } + + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); + + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + var rows = implementation(m_Connection, m_Transaction); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; + } + } - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// execute as an asynchronous operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var cmd = new SqlCommand()) { - var rows = implementation(m_Connection, m_Transaction); + cmd.Connection = m_Connection; + cmd.Transaction = m_Transaction; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + CommandFixup(executionToken, cmd); + + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } - catch (Exception ex) - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } } - - /// - /// execute as an asynchronous operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var cmd = new SqlCommand()) - { - cmd.Connection = m_Connection; - cmd.Transaction = m_Transaction; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + catch (Exception ex) + { + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - var rows = await implementation(m_Connection, m_Transaction, cancellationToken).ConfigureAwait(false); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Utilities.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Utilities.cs index 16c2263ad..4c825ac87 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Utilities.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServer/Utilities.cs @@ -1,72 +1,96 @@ using System.Data.Common; using Tortuga.Chain.CommandBuilders; -namespace Tortuga.Chain.SqlServer +namespace Tortuga.Chain.SqlServer; + +internal static class Utilities { - internal static class Utilities + /// + /// Gets the parameters from a SQL Builder. + /// + /// The SQL builder. + /// + public static List GetParameters(this SqlBuilder sqlBuilder) { - /// - /// Gets the parameters from a SQL Builder. - /// - /// The SQL builder. - /// - public static List GetParameters(this SqlBuilder sqlBuilder) - { - return sqlBuilder.GetParameters(ParameterBuilderCallback); - } + return sqlBuilder.GetParameters(ParameterBuilderCallback); + } + public static SqlParameter ParameterBuilderCallback(SqlBuilderEntry entry) + { + var result = new SqlParameter(); + result.ParameterName = entry.Details.SqlVariableName; - public static SqlParameter ParameterBuilderCallback(SqlBuilderEntry entry) +#if NET6_0_OR_GREATER + result.Value = entry.ParameterValue switch { - var result = new SqlParameter(); - result.ParameterName = entry.Details.SqlVariableName; - result.Value = entry.ParameterValue; + DateOnly dateOnly => dateOnly.ToDateTime(default), + TimeOnly timeOnly => timeOnly.ToTimeSpan(), + _ => entry.ParameterValue + }; +#else + result.Value = entry.ParameterValue; +#endif - if (entry.Details.DbType.HasValue) - { - result.SqlDbType = entry.Details.DbType.Value; + if (entry.Details.DbType.HasValue) + { + result.SqlDbType = entry.Details.DbType.Value; - if (entry.Details.MaxLength.HasValue) + if (entry.Details.MaxLength.HasValue) + { + switch (result.SqlDbType) { - switch (result.SqlDbType) - { - case SqlDbType.Char: - case SqlDbType.VarChar: - case SqlDbType.NChar: - case SqlDbType.NVarChar: - case SqlDbType.Binary: - case SqlDbType.VarBinary: - result.Size = entry.Details.MaxLength.Value; - break; - } + case SqlDbType.Char: + case SqlDbType.VarChar: + case SqlDbType.NChar: + case SqlDbType.NVarChar: + case SqlDbType.Binary: + case SqlDbType.VarBinary: + result.Size = entry.Details.MaxLength.Value; + break; } } + } - if (entry.ParameterValue is DbDataReader) - result.SqlDbType = SqlDbType.Structured; + if (entry.ParameterValue is DbDataReader) + result.SqlDbType = SqlDbType.Structured; - result.Direction = entry.Details.Direction; + result.Direction = entry.Details.Direction; - return result; - } + return result; + } - /// - /// Triggers need special handling for OUTPUT clauses. - /// - public static void UseTableVariable(this SqlBuilder sqlBuilder, SqlServerTableOrViewMetadata Table, out string? header, out string? intoClause, out string? footer) where TDbType : struct + public static bool RequiresSorting(this SqlServerLimitOption limitOption) + { + return limitOption switch { - if (sqlBuilder.HasReadFields && Table.HasTriggers) - { - header = "DECLARE @ResultTable TABLE( " + string.Join(", ", sqlBuilder.GetSelectColumnDetails().Select(c => c.QuotedSqlName + " " + c.FullTypeName + " NULL")) + ");" + Environment.NewLine; - intoClause = " INTO @ResultTable "; - footer = Environment.NewLine + "SELECT * FROM @ResultTable"; - } - else - { - header = null; - intoClause = null; - footer = null; - } + SqlServerLimitOption.None => false, + SqlServerLimitOption.Rows => true, + SqlServerLimitOption.Percentage => true, + SqlServerLimitOption.RowsWithTies => true, + SqlServerLimitOption.PercentageWithTies => true, + SqlServerLimitOption.TableSampleSystemRows => false, + SqlServerLimitOption.TableSampleSystemPercentage => false, + _ => throw new ArgumentOutOfRangeException(nameof(limitOption), limitOption, "Unknown limit option") + }; + } + + /// + /// Triggers need special handling for OUTPUT clauses. + /// + public static void UseTableVariable(this SqlBuilder sqlBuilder, SqlServerTableOrViewMetadata table, out string? header, out string? intoClause, out string? footer) + where TDbType : struct + { + if (sqlBuilder.HasReadFields && table.HasTriggers) + { + header = "DECLARE @ResultTable TABLE( " + string.Join(", ", sqlBuilder.GetSelectColumnDetails().Select(c => c.QuotedSqlName + " " + c.FullTypeName + " NULL")) + ");" + Environment.NewLine; + intoClause = " INTO @ResultTable "; + footer = Environment.NewLine + "SELECT * FROM @ResultTable"; + } + else + { + header = null; + intoClause = null; + footer = null; } } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerDataSource.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerDataSource.cs index 6b8d33a87..f6813ea48 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerDataSource.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerDataSource.cs @@ -4,481 +4,462 @@ using Tortuga.Chain.Core; using Tortuga.Chain.SqlServer; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class SqlServerDataSource. +/// +/// +public partial class SqlServerDataSource : SqlServerDataSourceBase { + readonly object m_SyncRoot = new object(); + SqlServerMetadataCache m_DatabaseMetadata; + bool m_IsSqlDependencyActive; + /// - /// Class SqlServerDataSource. + /// Initializes a new instance of the class. /// - /// - public partial class SqlServerDataSource : SqlServerDataSourceBase + /// Name of the data source. + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + public SqlServerDataSource(string? name, string connectionString, SqlServerDataSourceSettings? settings = null) : base(settings) { - SqlServerMetadataCache m_DatabaseMetadata; - - readonly object m_SyncRoot = new object(); - bool m_IsSqlDependencyActive; - - /// - /// Initializes a new instance of the class. - /// - /// Name of the data source. - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - public SqlServerDataSource(string? name, string connectionString, SqlServerDataSourceSettings? settings = null) : base(settings) + if (string.IsNullOrEmpty(connectionString)) + throw new ArgumentException("connectionString is null or empty.", nameof(connectionString)); + + m_ConnectionBuilder = new SqlConnectionStringBuilder(connectionString); + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.InitialCatalog ?? m_ConnectionBuilder.DataSource; + else + Name = name; + + m_DatabaseMetadata = new SqlServerMetadataCache(m_ConnectionBuilder); + + if (settings != null) { - if (string.IsNullOrEmpty(connectionString)) - throw new ArgumentException("connectionString is null or empty.", nameof(connectionString)); + XactAbort = settings.XactAbort; + ArithAbort = settings.ArithAbort; + } - m_ConnectionBuilder = new SqlConnectionStringBuilder(connectionString); - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.InitialCatalog ?? m_ConnectionBuilder.DataSource; - else - Name = name; + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - m_DatabaseMetadata = new SqlServerMetadataCache(m_ConnectionBuilder); + /// + /// Initializes a new instance of the class. + /// + /// The connection string. + /// Optional settings object. + /// connectionString is null or empty.;connectionString + public SqlServerDataSource(string connectionString, SqlServerDataSourceSettings? settings = null) + : this(null, connectionString, settings) + { + } - if (settings != null) - { - XactAbort = settings.XactAbort; - ArithAbort = settings.ArithAbort; - } + /// + /// Initializes a new instance of the class. + /// + /// Optional name of the data source. + /// The connection string builder. + /// Optional settings object. + /// connectionStringBuilder;connectionStringBuilder is null. + public SqlServerDataSource(string? name, SqlConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) : base(settings) + { + if (connectionStringBuilder == null) + throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + m_ConnectionBuilder = connectionStringBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.InitialCatalog ?? m_ConnectionBuilder.DataSource; + else + Name = name; + + m_DatabaseMetadata = new SqlServerMetadataCache(m_ConnectionBuilder); - /// - /// Initializes a new instance of the class. - /// - /// The connection string. - /// Optional settings object. - /// connectionString is null or empty.;connectionString - public SqlServerDataSource(string connectionString, SqlServerDataSourceSettings? settings = null) - : this(null, connectionString, settings) + if (settings != null) { + XactAbort = settings.XactAbort; + ArithAbort = settings.ArithAbort; } + m_ExtensionCache = new ConcurrentDictionary(); + m_Cache = DefaultCache; + } - /// - /// Initializes a new instance of the class. - /// - /// Optional name of the data source. - /// The connection string builder. - /// Optional settings object. - /// connectionStringBuilder;connectionStringBuilder is null. - public SqlServerDataSource(string? name, SqlConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) : base(settings) - { - if (connectionStringBuilder == null) - throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + /// + /// Initializes a new instance of the class. + /// + /// The connection string builder. + /// Optional settings object. + public SqlServerDataSource(SqlConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) + : this(null, connectionStringBuilder, settings) + { + } - m_ConnectionBuilder = connectionStringBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.InitialCatalog ?? m_ConnectionBuilder.DataSource; - else - Name = name; + SqlServerDataSource(string? name, SqlConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings settings, SqlServerMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + { + if (connectionStringBuilder == null) + throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); - m_DatabaseMetadata = new SqlServerMetadataCache(m_ConnectionBuilder); + m_ConnectionBuilder = connectionStringBuilder; + if (string.IsNullOrEmpty(name)) + Name = m_ConnectionBuilder.InitialCatalog ?? m_ConnectionBuilder.DataSource; + else + Name = name; - if (settings != null) - { - XactAbort = settings.XactAbort; - ArithAbort = settings.ArithAbort; - } - m_ExtensionCache = new ConcurrentDictionary(); - m_Cache = DefaultCache; - } + m_DatabaseMetadata = databaseMetadata; - SqlServerDataSource(string? name, SqlConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings settings, SqlServerMetadataCache databaseMetadata, ICacheAdapter cache, ConcurrentDictionary extensionCache) : base(settings) + if (settings != null) { - if (connectionStringBuilder == null) - throw new ArgumentNullException(nameof(connectionStringBuilder), $"{nameof(connectionStringBuilder)} is null."); + XactAbort = settings.XactAbort; + ArithAbort = settings.ArithAbort; + } + m_ExtensionCache = extensionCache; + m_Cache = cache; + } - m_ConnectionBuilder = connectionStringBuilder; - if (string.IsNullOrEmpty(name)) - Name = m_ConnectionBuilder.InitialCatalog ?? m_ConnectionBuilder.DataSource; - else - Name = name; + /// + /// Terminates a query when an overflow or divide-by-zero error occurs during query execution. + /// + /// Microsoft recommends setting ArithAbort=On for all connections. To avoid an additional round-trip to the server, do this at the server level instead of at the connection level. + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] + public bool? ArithAbort { get; } - m_DatabaseMetadata = databaseMetadata; + /// + /// This object can be used to lookup database information. + /// + public override SqlServerMetadataCache DatabaseMetadata + { + get { return m_DatabaseMetadata; } + } - if (settings != null) - { - XactAbort = settings.XactAbort; - ArithAbort = settings.ArithAbort; - } - m_ExtensionCache = extensionCache; - m_Cache = cache; - } + /// + /// Gets a value indicating whether SQL dependency support is active for this dispatcher. + /// + /// true if this SQL dependency is active; otherwise, false. + public bool IsSqlDependencyActive + { + get { return m_IsSqlDependencyActive; } + } - /// - /// Initializes a new instance of the class. - /// - /// The connection string builder. - /// Optional settings object. - public SqlServerDataSource(SqlConnectionStringBuilder connectionStringBuilder, SqlServerDataSourceSettings? settings = null) - : this(null, connectionStringBuilder, settings) - { - } + /// + /// Rolls back a transaction if a Transact-SQL statement raises a run-time error. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] + public bool? XactAbort { get; } - /// - /// Terminates a query when an overflow or divide-by-zero error occurs during query execution. - /// - /// Microsoft recommends setting ArithAbort=On for all connections. To avoid an additional round-trip to the server, do this at the server level instead of at the connection level. - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Arith")] - public bool? ArithAbort { get; } - - /// - /// This object can be used to lookup database information. - /// - public override SqlServerMetadataCache DatabaseMetadata - { - get { return m_DatabaseMetadata; } - } + /// + /// Creates a new transaction + /// + /// optional name of the transaction. + /// the isolation level. if not supplied, will use the database default. + /// if true, logging events are forwarded to the parent connection. + /// + /// + /// the caller of this function is responsible for closing the transaction. + /// + public virtual SqlServerTransactionalDataSource BeginTransaction(string? transactionName, IsolationLevel? isolationLevel = null, bool forwardEvents = true) + { + return new SqlServerTransactionalDataSource(this, transactionName, isolationLevel, forwardEvents); + } + /// + /// Creates a new transaction + /// + /// Name of the transaction. + /// The isolation level. + /// if set to true [forward events]. + /// + /// + public async Task BeginTransactionAsync(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true, CancellationToken cancellationToken = default) + { + var connection = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false); + + SqlTransaction transaction; + if (isolationLevel.HasValue) + transaction = connection.BeginTransaction(isolationLevel.Value); + else + transaction = connection.BeginTransaction(); + return new SqlServerTransactionalDataSource(this, transactionName, forwardEvents, connection, transaction); + } - /// - /// Gets a value indicating whether SQL dependency support is active for this dispatcher. - /// - /// true if this SQL dependency is active; otherwise, false. - public bool IsSqlDependencyActive + /// + /// Gets the options that are currently in effect. This takes into account server-defined defaults. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public SqlServerEffectiveSettings GetEffectiveSettings() + { + var result = new SqlServerEffectiveSettings(); + using (var con = CreateConnection()) + result.Reload(con, null); + return result; + } + + /// + /// Gets the options that are currently in effect. This takes into account server-defined defaults. + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public async Task GetEffectiveSettingsAsync() + { + var result = new SqlServerEffectiveSettings(); + using (var con = await CreateConnectionAsync().ConfigureAwait(false)) + await result.ReloadAsync(con, null).ConfigureAwait(false); + return result; + } + + /// + /// Starts SQL dependency on this connection string. + /// + /// + /// true if the listener initialized successfully; false if a compatible listener + /// already exists. + /// + public bool StartSqlDependency() + { + if (IsSqlDependencyActive) + throw new InvalidOperationException("SQL Dependency is currently active"); + + lock (m_SyncRoot) { - get { return m_IsSqlDependencyActive; } + m_IsSqlDependencyActive = true; + return SqlDependency.Start(ConnectionString); } + } + /// + /// Stops SQL dependency on this connection string. + /// + /// + /// true if the listener was completely stopped; false if the System.AppDomain + /// was unbound from the listener, but there are is at least one other System.AppDomain + /// using the same listener. + /// + public bool StopSqlDependency() + { + if (!IsSqlDependencyActive) + throw new InvalidOperationException("SQL Dependency is not currently active"); - /// - /// Rolls back a transaction if a Transact-SQL statement raises a run-time error. - /// - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xact")] - public bool? XactAbort { get; } - - /// - /// Creates a new transaction - /// - /// optional name of the transaction. - /// the isolation level. if not supplied, will use the database default. - /// if true, logging events are forwarded to the parent connection. - /// - /// - /// the caller of this function is responsible for closing the transaction. - /// - public virtual SqlServerTransactionalDataSource BeginTransaction(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true) + lock (m_SyncRoot) { - return new SqlServerTransactionalDataSource(this, transactionName, isolationLevel, forwardEvents); + m_IsSqlDependencyActive = false; + return SqlDependency.Stop(ConnectionString); } + } - /// - /// Creates a new transaction - /// - /// Name of the transaction. - /// The isolation level. - /// if set to true [forward events]. - /// - /// - public async Task BeginTransactionAsync(string? transactionName = null, IsolationLevel? isolationLevel = null, bool forwardEvents = true, CancellationToken cancellationToken = default) + /// + /// Creates a new data source with the indicated changes to the settings. + /// + /// The new settings to use. + /// + /// The new data source will share the same database metadata cache. + public SqlServerDataSource WithSettings(SqlServerDataSourceSettings? settings) + { + var mergedSettings = new SqlServerDataSourceSettings() { - var connection = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false); + DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, + SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, + StrictMode = settings?.StrictMode ?? StrictMode, + SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode, + XactAbort = settings?.XactAbort ?? XactAbort, + ArithAbort = settings?.ArithAbort ?? ArithAbort + }; + var result = new SqlServerDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); + result.m_DatabaseMetadata = m_DatabaseMetadata; + result.AuditRules = AuditRules; + result.UserValue = UserValue; + + result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); + result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); + result.ExecutionError += (sender, e) => OnExecutionError(e); + result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); + + return result; + } - SqlTransaction transaction; - if (isolationLevel.HasValue) - transaction = connection.BeginTransaction(isolationLevel.Value); - else - transaction = connection.BeginTransaction(); - return new SqlServerTransactionalDataSource(this, transactionName, forwardEvents, connection, transaction); - } + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// User supplied state. + [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] + protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Gets the options that are currently in effect. This takes into account server-defined defaults. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public SqlServerEffectiveSettings GetEffectiveSettings() + try { - var result = new SqlServerEffectiveSettings(); using (var con = CreateConnection()) - result.Reload(con, null); - return result; - } + { + using (var cmd = new SqlCommand()) + { + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); - /// - /// Gets the options that are currently in effect. This takes into account server-defined defaults. - /// - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public async Task GetEffectiveSettingsAsync() + CommandFixup(executionToken, cmd); + + var rows = implementation(cmd); + executionToken.RaiseCommandExecuted(cmd, rows); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; + } + } + } + catch (Exception ex) { - var result = new SqlServerEffectiveSettings(); - using (var con = await CreateConnectionAsync().ConfigureAwait(false)) - await result.ReloadAsync(con, null).ConfigureAwait(false); - return result; + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } + /// + /// Executes the specified operation. + /// + /// The execution token. + /// The implementation. + /// The state. + protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - /// - /// Starts SQL dependency on this connection string. - /// - /// - /// true if the listener initialized successfully; false if a compatible listener - /// already exists. - /// - public bool StartSqlDependency() - { - if (IsSqlDependencyActive) - throw new InvalidOperationException("SQL Dependency is currently active"); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - lock (m_SyncRoot) + try + { + using (var con = CreateConnection()) { - m_IsSqlDependencyActive = true; - return SqlDependency.Start(ConnectionString); + var rows = implementation(con, null); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Stops SQL dependency on this connection string. - /// - /// - /// true if the listener was completely stopped; false if the System.AppDomain - /// was unbound from the listener, but there are is at least one other System.AppDomain - /// using the same listener. - /// - public bool StopSqlDependency() + catch (Exception ex) { - if (!IsSqlDependencyActive) - throw new InvalidOperationException("SQL Dependency is not currently active"); - - lock (m_SyncRoot) - { - m_IsSqlDependencyActive = false; - return SqlDependency.Stop(ConnectionString); - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } + } + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation. + /// The cancellation token. + /// The state. + /// Task. + protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// User supplied state. - [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")] - protected override int? Execute(CommandExecutionToken executionToken, CommandImplementation implementation, object? state) + try { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try - { - using (var con = CreateConnection()) - { - using (var cmd = new SqlCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = implementation(cmd); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } - } - catch (Exception ex) + using (var con = CreateConnection()) { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; + var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); + return rows; } } - - /// - /// Executes the specified operation. - /// - /// The execution token. - /// The implementation. - /// The state. - protected override int? Execute(OperationExecutionToken executionToken, OperationImplementation implementation, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = CreateConnection()) - { - var rows = implementation(con, null); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); throw; } } + } - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation. - /// The cancellation token. - /// The state. - /// Task. - protected override async Task ExecuteAsync(OperationExecutionToken executionToken, OperationImplementationAsync implementation, CancellationToken cancellationToken, object? state) - { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); + /// + /// Execute the operation asynchronously. + /// + /// The execution token. + /// The implementation that handles processing the result of the command. + /// The cancellation token. + /// User supplied state. + /// Task. + protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + { + if (executionToken == null) + throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); + if (implementation == null) + throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); + var startTime = DateTimeOffset.Now; + OnExecutionStarted(executionToken, startTime, state); - try + try + { + using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) { - using (var con = CreateConnection()) + using (var cmd = new SqlCommand()) { - var rows = await implementation(con, null, cancellationToken).ConfigureAwait(false); + cmd.Connection = con; + executionToken.PopulateCommand(cmd, DefaultCommandTimeout); + + CommandFixup(executionToken, cmd); + + var rows = await implementation(cmd).ConfigureAwait(false); + executionToken.RaiseCommandExecuted(cmd, rows); OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); return rows; } } - catch (Exception ex) - { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } - } } - - /// - /// Execute the operation asynchronously. - /// - /// The execution token. - /// The implementation that handles processing the result of the command. - /// The cancellation token. - /// User supplied state. - /// Task. - protected override async Task ExecuteAsync(CommandExecutionToken executionToken, CommandImplementationAsync implementation, CancellationToken cancellationToken, object? state) + catch (Exception ex) { - if (executionToken == null) - throw new ArgumentNullException(nameof(executionToken), $"{nameof(executionToken)} is null."); - if (implementation == null) - throw new ArgumentNullException(nameof(implementation), $"{nameof(implementation)} is null."); - - var startTime = DateTimeOffset.Now; - OnExecutionStarted(executionToken, startTime, state); - - try + if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException { - using (var con = await CreateConnectionAsync(cancellationToken).ConfigureAwait(false)) - { - using (var cmd = new SqlCommand()) - { - cmd.Connection = con; - if (DefaultCommandTimeout.HasValue) - cmd.CommandTimeout = (int)DefaultCommandTimeout.Value.TotalSeconds; - cmd.CommandText = executionToken.CommandText; - cmd.CommandType = executionToken.CommandType; - foreach (var param in executionToken.Parameters) - cmd.Parameters.Add(param); - - executionToken.ApplyCommandOverrides(cmd); - - var rows = await implementation(cmd).ConfigureAwait(false); - executionToken.RaiseCommandExecuted(cmd, rows); - OnExecutionFinished(executionToken, startTime, DateTimeOffset.Now, rows, state); - return rows; - } - } + var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); + OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); + throw ex2; } - catch (Exception ex) + else { - if (cancellationToken.IsCancellationRequested) //convert Exception into a OperationCanceledException - { - var ex2 = new OperationCanceledException("Operation was canceled.", ex, cancellationToken); - OnExecutionCanceled(executionToken, startTime, DateTimeOffset.Now, state); - throw ex2; - } - else - { - OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); - throw; - } + OnExecutionError(executionToken, startTime, DateTimeOffset.Now, ex, state); + throw; } } + } - string? BuildConnectionSettingsOverride() - { - if (DatabaseMetadata.ServerDefaultSettings == null) - throw new InvalidOperationException("m_ServerDefaultSettings was not set before building connection settings."); - - if (ArithAbort == null && XactAbort == null) - return null; - - var sql = new StringBuilder(); - - if (ArithAbort.HasValue && ArithAbort != DatabaseMetadata.ServerDefaultSettings.ArithAbort) - sql.AppendLine("SET ARITHABORT " + (ArithAbort.Value ? "ON" : "OFF")); - if (XactAbort.HasValue && XactAbort != DatabaseMetadata.ServerDefaultSettings.XactAbort) - sql.AppendLine("SET XACT_ABORT " + (XactAbort.Value ? "ON" : "OFF")); + string? BuildConnectionSettingsOverride() + { + if (DatabaseMetadata.ServerDefaultSettings == null) + throw new InvalidOperationException("m_ServerDefaultSettings was not set before building connection settings."); - return sql.ToString(); - } + if (ArithAbort == null && XactAbort == null) + return null; + var sql = new StringBuilder(); - /// - /// Creates a new data source with the indicated changes to the settings. - /// - /// The new settings to use. - /// - /// The new data source will share the same database metadata cache. - public SqlServerDataSource WithSettings(SqlServerDataSourceSettings? settings) - { - var mergedSettings = new SqlServerDataSourceSettings() - { - DefaultCommandTimeout = settings?.DefaultCommandTimeout ?? DefaultCommandTimeout, - SuppressGlobalEvents = settings?.SuppressGlobalEvents ?? SuppressGlobalEvents, - StrictMode = settings?.StrictMode ?? StrictMode, - SequentialAccessMode = settings?.SequentialAccessMode ?? SequentialAccessMode, - XactAbort = settings?.XactAbort ?? XactAbort, - ArithAbort = settings?.ArithAbort ?? ArithAbort - }; - var result = new SqlServerDataSource(Name, m_ConnectionBuilder, mergedSettings, m_DatabaseMetadata, m_Cache, m_ExtensionCache); - result.m_DatabaseMetadata = m_DatabaseMetadata; - result.AuditRules = AuditRules; - result.UserValue = UserValue; - - result.ExecutionStarted += (sender, e) => OnExecutionStarted(e); - result.ExecutionFinished += (sender, e) => OnExecutionFinished(e); - result.ExecutionError += (sender, e) => OnExecutionError(e); - result.ExecutionCanceled += (sender, e) => OnExecutionCanceled(e); - - return result; - } + if (ArithAbort.HasValue && ArithAbort != DatabaseMetadata.ServerDefaultSettings.ArithAbort) + sql.AppendLine("SET ARITHABORT " + (ArithAbort.Value ? "ON" : "OFF")); + if (XactAbort.HasValue && XactAbort != DatabaseMetadata.ServerDefaultSettings.XactAbort) + sql.AppendLine("SET XACT_ABORT " + (XactAbort.Value ? "ON" : "OFF")); + return sql.ToString(); } -} +} \ No newline at end of file diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerExtensions.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerExtensions.cs index 456783a8d..cc276bc06 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerExtensions.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerExtensions.cs @@ -1,48 +1,47 @@ using System.Collections.Concurrent; using Tortuga.Chain.SqlServer; -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Class SqlServerExtensions. +/// +public static class SqlServerExtensions { + readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + /// - /// Class SqlServerExtensions. + /// Returns a data source wrapped around the connection. /// - public static class SqlServerExtensions + /// The connection. + /// SqlServerOpenDataSource. + /// + public static SqlServerOpenDataSource AsDataSource(this SqlConnection connection) { - readonly static ConcurrentDictionary s_CachedDataSources = new ConcurrentDictionary(); + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - /// - /// Returns a data source wrapped around the connection. - /// - /// The connection. - /// SqlServerOpenDataSource. - /// - public static SqlServerOpenDataSource AsDataSource(this SqlConnection connection) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); - - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SqlServerDataSource(cs)); - return new SqlServerOpenDataSource(dataSourceBase, connection, null); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SqlServerDataSource(cs)); + return new SqlServerOpenDataSource(dataSourceBase, connection, null); + } - /// - /// Returns a data source wrapped around the transaction. - /// - /// The connection. - /// The transaction. - /// SqlServerOpenDataSource. - /// - public static SqlServerOpenDataSource AsDataSource(this SqlConnection connection, SqlTransaction transaction) - { - if (connection == null) - throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); - if (connection.State == ConnectionState.Closed) - connection.Open(); + /// + /// Returns a data source wrapped around the transaction. + /// + /// The connection. + /// The transaction. + /// SqlServerOpenDataSource. + /// + public static SqlServerOpenDataSource AsDataSource(this SqlConnection connection, SqlTransaction transaction) + { + if (connection == null) + throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); + if (connection.State == ConnectionState.Closed) + connection.Open(); - var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SqlServerDataSource(cs)); - return new SqlServerOpenDataSource(dataSourceBase, connection, transaction); - } + var dataSourceBase = s_CachedDataSources.GetOrAdd(connection.ConnectionString, cs => new SqlServerDataSource(cs)); + return new SqlServerOpenDataSource(dataSourceBase, connection, transaction); } } diff --git a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerLimitOption.cs b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerLimitOption.cs index 708895ad3..96fb25ec0 100644 --- a/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerLimitOption.cs +++ b/Tortuga.Chain/Tortuga.Chain.SqlServer/shared/SqlServerLimitOption.cs @@ -1,44 +1,43 @@ -namespace Tortuga.Chain +namespace Tortuga.Chain; + +/// +/// Limit options supported by SQL Server. +/// +/// This is a strict subset of LimitOptions +public enum SqlServerLimitOption { /// - /// Limit options supported by SQL Server. + /// No limits were applied. /// - /// This is a strict subset of LimitOptions - public enum SqlServerLimitOption - { - /// - /// No limits were applied. - /// - None = LimitOptions.None, + None = LimitOptions.None, - /// - /// Uses OFFSET/FETCH - /// - Rows = LimitOptions.Rows, + /// + /// Uses OFFSET/FETCH + /// + Rows = LimitOptions.Rows, - /// - /// Uses TOP (N) PERCENT - /// - Percentage = LimitOptions.Percentage, + /// + /// Uses TOP (N) PERCENT + /// + Percentage = LimitOptions.Percentage, - /// - /// Uses TOP (N) WITH TIES - /// - RowsWithTies = LimitOptions.RowsWithTies, + /// + /// Uses TOP (N) WITH TIES + /// + RowsWithTies = LimitOptions.RowsWithTies, - /// - /// Uses TOP (N) PERCENT WITH TIES - /// - PercentageWithTies = LimitOptions.PercentageWithTies, + /// + /// Uses TOP (N) PERCENT WITH TIES + /// + PercentageWithTies = LimitOptions.PercentageWithTies, - /// - /// Uses TABLESAMPLE SYSTEM (N ROWS) - /// - TableSampleSystemRows = LimitOptions.TableSampleSystemRows, + /// + /// Uses TABLESAMPLE SYSTEM (N ROWS) + /// + TableSampleSystemRows = LimitOptions.TableSampleSystemRows, - /// - /// Uses TABLESAMPLE SYSTEM (N PERCENT) - /// - TableSampleSystemPercentage = LimitOptions.TableSampleSystemPercentage, - } + /// + /// Uses TABLESAMPLE SYSTEM (N PERCENT) + /// + TableSampleSystemPercentage = LimitOptions.TableSampleSystemPercentage, } diff --git a/Tortuga.Chain/Tortuga.Chain.sln b/Tortuga.Chain/Tortuga.Chain.sln index a54f34f7d..6dd3c7439 100644 --- a/Tortuga.Chain/Tortuga.Chain.sln +++ b/Tortuga.Chain/Tortuga.Chain.sln @@ -37,6 +37,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig Changelog.md = Changelog.md + Engineering Notes.md = Engineering Notes.md Shared\GlobalUsing.cs = Shared\GlobalUsing.cs Shared\GlobalUsingForTests.cs = Shared\GlobalUsingForTests.cs ..\README.md = ..\README.md