Skip to content

Commit

Permalink
Merge pull request #15 from cajuncoding/feature/avoid_schema_locks_as…
Browse files Browse the repository at this point in the history
…_default_behavior

Refactor and enhance to now avoid Schema Locks as default behavior in…
  • Loading branch information
cajuncoding committed Aug 8, 2023
2 parents 2c868c5 + 2fbc221 commit fdde00f
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 142 deletions.
17 changes: 13 additions & 4 deletions NetStandard.SqlBulkHelpers/Database/TableNameTerm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ public TableNameTerm(string schemaName, string tableName)
public string FullyQualifiedTableName { get; }

public override string ToString() => FullyQualifiedTableName;
public bool Equals(TableNameTerm other) => FullyQualifiedTableName.Equals(other.FullyQualifiedTableName);
public bool EqualsIgnoreCase(TableNameTerm other) => FullyQualifiedTableName.Equals(other.FullyQualifiedTableName, StringComparison.OrdinalIgnoreCase);
public TableNameTerm SwitchSchema(string newSchema) => new TableNameTerm(newSchema, TableName);


public bool Equals(TableNameTerm other)
=> FullyQualifiedTableName.Equals(other.FullyQualifiedTableName);

public bool EqualsIgnoreCase(TableNameTerm other)
=> FullyQualifiedTableName.Equals(other.FullyQualifiedTableName, StringComparison.OrdinalIgnoreCase);

public TableNameTerm SwitchSchema(string newSchema)
=> new TableNameTerm(newSchema, TableName);

public TableNameTerm ApplyNamePrefixOrSuffix(string prefix = null, string suffix = null)
=> new TableNameTerm(SchemaName, string.Concat(prefix?.Trim() ?? string.Empty, TableName, suffix?.Trim() ?? string.Empty));

//Handle Automatic String conversions for simplified APIs...
public static implicit operator string(TableNameTerm t) => t.ToString();

Expand Down
16 changes: 8 additions & 8 deletions NetStandard.SqlBulkHelpers/MaterializedData/CloneTableInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public CloneTableInfo MakeTargetTableNameUnique()
=> new CloneTableInfo(SourceTable, MakeTableNameUniqueInternal(TargetTable));

private static TableNameTerm MakeTableNameUniqueInternal(TableNameTerm tableNameTerm)
=> TableNameTerm.From(tableNameTerm.SchemaName, $"{tableNameTerm.TableName}_Copy_{IdGenerator.NewId(10)}");
=> TableNameTerm.From(tableNameTerm.SchemaName, string.Concat(tableNameTerm.TableName, "_", IdGenerator.NewId(10)));

public static CloneTableInfo From<TSource, TTarget>(string sourceTableName = null, string targetTableName = null)
public static CloneTableInfo From<TSource, TTarget>(string sourceTableName = null, string targetTableName = null, string targetPrefix = null, string targetSuffix = null)
{
//If the generic type is ISkipMappingLookup then we must have a valid sourceTableName specified as a param...
if (SqlBulkHelpersProcessingDefinition.SkipMappingLookupType.IsAssignableFrom(typeof(TSource)))
Expand All @@ -46,22 +46,22 @@ private static TableNameTerm MakeTableNameUniqueInternal(TableNameTerm tableName
? sourceTableName
: targetTableName;

//If the generic type is ISkipMappingLookup then we must have a valid sourceTableName specified as a param...
//If the generic type is ISkipMappingLookup then we must have a valid validTargetTableName specified as a param...
if (SqlBulkHelpersProcessingDefinition.SkipMappingLookupType.IsAssignableFrom(typeof(TTarget)))
{
//We validate the valid target table name but if it's still blank then we throw an Argument
// exception because no 'targetTableName' could be resolved...
validTargetTableName.AssertArgumentIsNotNullOrWhiteSpace(nameof(targetTableName));
}

var targetTable = TableNameTerm.From<TTarget>(targetTableName ?? sourceTableName);
var targetTable = TableNameTerm.From<TTarget>(targetTableName ?? sourceTableName).ApplyNamePrefixOrSuffix(targetPrefix, targetSuffix);
return new CloneTableInfo(sourceTable, targetTable);
}

public static CloneTableInfo From(string sourceTableName, string targetTableName = null)
=> From<ISkipMappingLookup, ISkipMappingLookup>(sourceTableName, targetTableName);
public static CloneTableInfo From(string sourceTableName, string targetTableName = null, string targetPrefix = null, string targetSuffix = null)
=> From<ISkipMappingLookup, ISkipMappingLookup>(sourceTableName, targetTableName, targetPrefix, targetSuffix);

public static CloneTableInfo ForNewSchema(TableNameTerm sourceTable, string targetSchemaName)
=> new CloneTableInfo(sourceTable, sourceTable.SwitchSchema(targetSchemaName));
public static CloneTableInfo ForNewSchema(TableNameTerm sourceTable, string targetSchemaName, string targetTablePrefix = null, string targetTableSuffix = null)
=> new CloneTableInfo(sourceTable, sourceTable.SwitchSchema(targetSchemaName).ApplyNamePrefixOrSuffix(targetTablePrefix, targetTableSuffix));
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;

namespace SqlBulkHelpers.MaterializedData
{
public interface IMaterializeDataContextCompletionSource : IMaterializeDataContext
{
Task FinishMaterializeDataProcessAsync();
Task FinishMaterializeDataProcessAsync(SqlTransaction sqlTransaction);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace SqlBulkHelpers.MaterializedData
{
public class MaterializeDataContext : IMaterializeDataContextCompletionSource, IMaterializeDataContext
{
protected SqlTransaction SqlTransaction { get; }
protected ILookup<string, MaterializationTableInfo> TableLookupByFullyQualifiedName { get; }
protected ILookup<string, MaterializationTableInfo> TableLookupByOriginalName { get; }
protected ISqlBulkHelpersConfig BulkHelpersConfig { get; }
Expand Down Expand Up @@ -80,16 +79,15 @@ public MaterializationTableInfo FindMaterializationTableInfoCaseInsensitive(Type
/// </summary>
public bool EnableDataConstraintChecksOnCompletion { get; set; } = true;

public MaterializeDataContext(SqlTransaction sqlTransaction, MaterializationTableInfo[] materializationTables, ISqlBulkHelpersConfig bulkHelpersConfig)
public MaterializeDataContext(MaterializationTableInfo[] materializationTables, ISqlBulkHelpersConfig bulkHelpersConfig)
{
SqlTransaction = sqlTransaction.AssertArgumentIsNotNull(nameof(sqlTransaction));
Tables = materializationTables.AssertArgumentIsNotNull(nameof(materializationTables));
BulkHelpersConfig = bulkHelpersConfig.AssertArgumentIsNotNull(nameof(bulkHelpersConfig));
TableLookupByFullyQualifiedName = Tables.ToLookup(t => t.LiveTable.FullyQualifiedTableName, StringComparer.OrdinalIgnoreCase);
TableLookupByOriginalName = Tables.ToLookup(t => t.OriginalTableName, StringComparer.OrdinalIgnoreCase);
}

internal async Task HandleNonTransactionTasksBeforeMaterialization()
internal async Task HandleParallelConnectionTasksBeforeMaterialization()
{
//NOW JUST PRIOR to Executing the Materialized Data Switch we must handle any actions required outside of the Materialized Data Transaction (e.g. FullTextIndexes, etc.)
//NOTE: We do this here so that our live tables have the absolute minimum impact; meaning things like Full Text Indexes are Dropped for ONLY the amount of time it takes to execute our Switch
Expand Down Expand Up @@ -118,7 +116,7 @@ internal async Task HandleNonTransactionTasksBeforeMaterialization()
/// occurs during the Finish Materialization process!!!
/// </summary>
/// <returns></returns>
internal async Task HandleNonTransactionTasksAfterMaterialization()
internal async Task HandleParallelConnectionTasksAfterMaterialization()
{
if (TablesWithFullTextIndexesRemoved.Any())
{
Expand All @@ -134,7 +132,7 @@ internal async Task HandleNonTransactionTasksAfterMaterialization()
}
}

public async Task FinishMaterializeDataProcessAsync()
public async Task FinishMaterializeDataProcessAsync(SqlTransaction sqlTransaction)
{
var materializationTables = this.Tables;
var switchScriptBuilder = MaterializedDataScriptBuilder.NewSqlScript();
Expand Down Expand Up @@ -207,16 +205,10 @@ public async Task FinishMaterializeDataProcessAsync()
//NOTE: FKeys must be explicitly re-enabled to ensure they are restored to Trusted state; they aren't included in the ALL Constraint Check.
.EnableForeignKeyChecks(materializationTableInfo.LiveTable, this.EnableDataConstraintChecksOnCompletion, liveTableDefinition.ForeignKeyConstraints.AsArray())
//Re-enable All other Referencing FKey Checks that were disable above to allow the switching above...
.EnableReferencingForeignKeyChecks(this.EnableDataConstraintChecksOnCompletion, otherReferencingFKeyConstraints.AsArray())
//Finally cleanup the Loading and Discarding tables...
.DropTable(materializationTableInfo.LoadingTable)
.DropTable(materializationTableInfo.DiscardingTable);

.EnableReferencingForeignKeyChecks(this.EnableDataConstraintChecksOnCompletion, otherReferencingFKeyConstraints.AsArray());
}

//var timeoutConvertedToMinutes = Math.Max(1, (int)Math.Ceiling((decimal)BulkHelpersConfig.MaterializeDataStructureProcessingTimeoutSeconds / 60));

await SqlTransaction.ExecuteMaterializedDataSqlScriptAsync(
await sqlTransaction.ExecuteMaterializedDataSqlScriptAsync(
switchScriptBuilder,
BulkHelpersConfig.MaterializeDataStructureProcessingTimeoutSeconds
).ConfigureAwait(false);
Expand Down

0 comments on commit fdde00f

Please sign in to comment.