diff --git a/src/Gemstone.Data/Model/SecureTableOperations.cs b/src/Gemstone.Data/Model/SecureTableOperations.cs
index d5010ba6e..14ae9b7d0 100644
--- a/src/Gemstone.Data/Model/SecureTableOperations.cs
+++ b/src/Gemstone.Data/Model/SecureTableOperations.cs
@@ -23,6 +23,7 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
@@ -40,10 +41,6 @@ namespace Gemstone.Data.Model;
/// Modeled table.
public class SecureTableOperations where T : class, new()
{
- ///
- /// which performs DB operations.
- ///
- public TableOperations BaseOperations { get; }
///
/// Creates a new
@@ -63,8 +60,157 @@ public SecureTableOperations(AdoDataConnection connection)
BaseOperations = new(connection);
}
+ #region [ Properties ]
+
+ ///
+ /// which performs DB operations.
+ ///
+ public TableOperations BaseOperations { get; }
+
+ ///
+ /// Gets instance associated with this used for database operations.
+ ///
+ public AdoDataConnection Connection => BaseOperations.Connection;
+
+ ///
+ /// Gets the table name defined for the modeled table, includes any escaping as defined in model.
+ ///
+ public string TableName => BaseOperations.TableName;
+
+ ///
+ /// Gets the table name defined for the modeled table without any escape characters.
+ ///
+ ///
+ /// A table name will only be escaped if the model requested escaping with the .
+ ///
+ public string UnescapedTableName => BaseOperations.UnescapedTableName;
+
+ ///
+ /// Gets the wildcard character used for pattern matching within queries.
+ ///
+ public string WildcardChar => BaseOperations.WildcardChar;
+
+ ///
+ /// Gets flag that determines if modeled table has a primary key that is an identity field.
+ ///
+ public bool HasPrimaryKeyIdentityField => BaseOperations.HasPrimaryKeyIdentityField;
+
+ ///
+ /// Gets or sets delegate used to handle table operation exceptions.
+ ///
+ ///
+ /// When exception handler is provided, table operations will not throw exceptions for database calls, any
+ /// encountered exceptions will be passed to handler for processing. Otherwise, exceptions will be thrown
+ /// on the call stack.
+ ///
+ public Action? ExceptionHandler => BaseOperations.ExceptionHandler;
+
+ ///
+ /// Gets or sets flag that determines if field names should be treated as case-sensitive. Defaults to false.
+ ///
+ ///
+ /// In cases where modeled table fields have applied , this flag will be used
+ /// to properly update escaped field names that may be case-sensitive. For example, escaped field names in Oracle
+ /// are case-sensitive. This value is typically false.
+ ///
+ public bool UseCaseSensitiveFieldNames => BaseOperations.UseCaseSensitiveFieldNames;
+
+ ///
+ /// Gets or sets primary key cache.
+ ///
+ ///
+ ///
+ /// The overloads that include paging parameters
+ /// cache the sorted and filtered primary keys of queried records between calls so that paging is fast and
+ /// efficient. Since the primary keys are cached, an instance of the should
+ /// exist per user session when using query functions that support pagination. In web based implementations,
+ /// the primary cache should be stored with user session state data and then restored between instances of
+ /// the that are created along with a connection that is opened per page.
+ ///
+ ///
+ /// The function should be called to manually clear cache when table
+ /// contents are known to have changed. Note that calls to any overload
+ /// will automatically clear any existing primary key cache.
+ ///
+ ///
+ /// Primary keys values are stored in data table without interpretation, i.e., in their raw form as queried
+ /// from the database. Primary key data in cache will be encrypted for models with primary key fields that
+ /// are marked with the
+ ///
+ ///
+ public DataTable? PrimaryKeyCache => BaseOperations.PrimaryKeyCache;
+
+ ///
+ /// Gets or sets root record restriction that applies to query table operations.
+ ///
+ ///
+ ///
+ /// Defining a root query restriction creates a base query filter that gets applied to all query operations,
+ /// even when another restriction is applied - in this case the root restriction will be pre-pended to the
+ /// specified query, e.g.:
+ ///
+ /// restriction = RootQueryRestriction + restriction;
+ ///
+ /// A root query restriction is useful to apply a common state to the query operations, e.g., always
+ /// filtering records for a specific user or context.
+ ///
+ ///
+ /// A root query restriction can be manually assigned to a instance or
+ /// automatically assigned by marking a model with the .
+ ///
+ ///
+ /// If any of the reference a table field that is modeled with
+ /// either an or , then the function
+ /// will need to be called, replacing the target parameter with the
+ /// returned value so that the field value will be properly set prior to executing the database function.
+ ///
+ ///
+ public RecordRestriction? RootQueryRestriction => BaseOperations.RootQueryRestriction;
+
+ ///
+ /// Gets or sets flag that determines if should be applied to update operations.
+ ///
+ ///
+ ///
+ /// If only references primary key fields, then this property value should be set
+ /// to false since default update operations for a modeled record already work against primary key fields.
+ ///
+ ///
+ /// This flag can be manually set per instance or handled automatically by marking
+ /// a model with the and assigning a value to the attribute property
+ /// .
+ ///
+ ///
+ public bool ApplyRootQueryRestrictionToUpdates => BaseOperations.ApplyRootQueryRestrictionToUpdates;
+
+ ///
+ /// Gets or sets flag that determines if should be applied to delete operations.
+ ///
+ ///
+ ///
+ /// If only references primary key fields, then this property value should be set
+ /// to false since default delete operations for a modeled record already work against primary key fields.
+ ///
+ ///
+ /// This flag can be manually set per instance or handled automatically by marking
+ /// a model with the and assigning a value to the attribute property
+ /// .
+ ///
+ ///
+ public bool ApplyRootQueryRestrictionToDeletes => BaseOperations.ApplyRootQueryRestrictionToDeletes;
+
+ #endregion
+
#region [ Methods ]
+ ///
+ /// Creates a new modeled record instance, applying any modeled default values as specified by a
+ /// or on the
+ /// model properties.
+ ///
+ /// New modeled record instance with any defined default values applied.
+ public T? NewRecord() => BaseOperations.NewRecord();
+
///
/// Transforms a into an equivalent , as defined by the model's .
///
@@ -793,6 +939,43 @@ public int DeleteRecord(ClaimsPrincipal principal, RecordRestriction? restrictio
public Task DeleteRecordAsync(ClaimsPrincipal principal, RecordRestriction? restriction, CancellationToken cancellationToken, bool? applyRootQueryRestriction = null) =>
BaseOperations.DeleteRecordAsync(restriction + GetClaimRecordRestriction(principal), cancellationToken, applyRootQueryRestriction);
+ ///
+ /// Deletes the specified modeled table from the database.
+ ///
+ /// Claims principal which is making the request.
+ /// Record to delete.
+ /// Number of rows affected.
+ public int DeleteRecord(ClaimsPrincipal principal, T record)
+ {
+ IEnumerable whereElements = BaseOperations
+ .GetPrimaryKeyFieldNames(true)
+ .Select((primaryKeyField, index) => $"{primaryKeyField} = {index}");
+ RecordRestriction recordRestrict = new RecordRestriction(
+ string.Join(" AND ", whereElements),
+ BaseOperations.GetPrimaryKeys(record)
+ );
+ return DeleteRecord(principal, recordRestrict);
+ }
+
+ ///
+ /// Deletes the specified modeled table from the database.
+ ///
+ /// Claims principal which is making the request.
+ /// Record to delete.
+ /// Propagates notification that operations should be canceled.
+ /// Number of rows affected.
+ public Task DeleteRecordAsync(ClaimsPrincipal principal, T record, CancellationToken cancellationToken)
+ {
+ IEnumerable whereElements = BaseOperations
+ .GetPrimaryKeyFieldNames(true)
+ .Select((primaryKeyField, index) => $"{primaryKeyField} = {index}");
+ RecordRestriction recordRestrict = new RecordRestriction(
+ string.Join(" AND ", whereElements),
+ BaseOperations.GetPrimaryKeys(record)
+ );
+ return DeleteRecordAsync(principal, recordRestrict, cancellationToken);
+ }
+
///
/// Deletes the records referenced by the specified SQL filter expression and parameters.
///