Skip to content

Commit fdde00f

Browse files
authored
Merge pull request #15 from cajuncoding/feature/avoid_schema_locks_as_default_behavior
Refactor and enhance to now avoid Schema Locks as default behavior in…
2 parents 2c868c5 + 2fbc221 commit fdde00f

File tree

12 files changed

+339
-142
lines changed

12 files changed

+339
-142
lines changed

NetStandard.SqlBulkHelpers/Database/TableNameTerm.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,19 @@ public TableNameTerm(string schemaName, string tableName)
2323
public string FullyQualifiedTableName { get; }
2424

2525
public override string ToString() => FullyQualifiedTableName;
26-
public bool Equals(TableNameTerm other) => FullyQualifiedTableName.Equals(other.FullyQualifiedTableName);
27-
public bool EqualsIgnoreCase(TableNameTerm other) => FullyQualifiedTableName.Equals(other.FullyQualifiedTableName, StringComparison.OrdinalIgnoreCase);
28-
public TableNameTerm SwitchSchema(string newSchema) => new TableNameTerm(newSchema, TableName);
29-
26+
27+
public bool Equals(TableNameTerm other)
28+
=> FullyQualifiedTableName.Equals(other.FullyQualifiedTableName);
29+
30+
public bool EqualsIgnoreCase(TableNameTerm other)
31+
=> FullyQualifiedTableName.Equals(other.FullyQualifiedTableName, StringComparison.OrdinalIgnoreCase);
32+
33+
public TableNameTerm SwitchSchema(string newSchema)
34+
=> new TableNameTerm(newSchema, TableName);
35+
36+
public TableNameTerm ApplyNamePrefixOrSuffix(string prefix = null, string suffix = null)
37+
=> new TableNameTerm(SchemaName, string.Concat(prefix?.Trim() ?? string.Empty, TableName, suffix?.Trim() ?? string.Empty));
38+
3039
//Handle Automatic String conversions for simplified APIs...
3140
public static implicit operator string(TableNameTerm t) => t.ToString();
3241

NetStandard.SqlBulkHelpers/MaterializedData/CloneTableInfo.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public CloneTableInfo MakeTargetTableNameUnique()
3030
=> new CloneTableInfo(SourceTable, MakeTableNameUniqueInternal(TargetTable));
3131

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

35-
public static CloneTableInfo From<TSource, TTarget>(string sourceTableName = null, string targetTableName = null)
35+
public static CloneTableInfo From<TSource, TTarget>(string sourceTableName = null, string targetTableName = null, string targetPrefix = null, string targetSuffix = null)
3636
{
3737
//If the generic type is ISkipMappingLookup then we must have a valid sourceTableName specified as a param...
3838
if (SqlBulkHelpersProcessingDefinition.SkipMappingLookupType.IsAssignableFrom(typeof(TSource)))
@@ -46,22 +46,22 @@ public static CloneTableInfo From<TSource, TTarget>(string sourceTableName = nul
4646
? sourceTableName
4747
: targetTableName;
4848

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

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

61-
public static CloneTableInfo From(string sourceTableName, string targetTableName = null)
62-
=> From<ISkipMappingLookup, ISkipMappingLookup>(sourceTableName, targetTableName);
61+
public static CloneTableInfo From(string sourceTableName, string targetTableName = null, string targetPrefix = null, string targetSuffix = null)
62+
=> From<ISkipMappingLookup, ISkipMappingLookup>(sourceTableName, targetTableName, targetPrefix, targetSuffix);
6363

64-
public static CloneTableInfo ForNewSchema(TableNameTerm sourceTable, string targetSchemaName)
65-
=> new CloneTableInfo(sourceTable, sourceTable.SwitchSchema(targetSchemaName));
64+
public static CloneTableInfo ForNewSchema(TableNameTerm sourceTable, string targetSchemaName, string targetTablePrefix = null, string targetTableSuffix = null)
65+
=> new CloneTableInfo(sourceTable, sourceTable.SwitchSchema(targetSchemaName).ApplyNamePrefixOrSuffix(targetTablePrefix, targetTableSuffix));
6666
}
6767
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System.Threading.Tasks;
2+
using Microsoft.Data.SqlClient;
23

34
namespace SqlBulkHelpers.MaterializedData
45
{
56
public interface IMaterializeDataContextCompletionSource : IMaterializeDataContext
67
{
7-
Task FinishMaterializeDataProcessAsync();
8+
Task FinishMaterializeDataProcessAsync(SqlTransaction sqlTransaction);
89
}
910
}

NetStandard.SqlBulkHelpers/MaterializedData/MaterializeDataContext.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ namespace SqlBulkHelpers.MaterializedData
99
{
1010
public class MaterializeDataContext : IMaterializeDataContextCompletionSource, IMaterializeDataContext
1111
{
12-
protected SqlTransaction SqlTransaction { get; }
1312
protected ILookup<string, MaterializationTableInfo> TableLookupByFullyQualifiedName { get; }
1413
protected ILookup<string, MaterializationTableInfo> TableLookupByOriginalName { get; }
1514
protected ISqlBulkHelpersConfig BulkHelpersConfig { get; }
@@ -80,16 +79,15 @@ public MaterializationTableInfo FindMaterializationTableInfoCaseInsensitive(Type
8079
/// </summary>
8180
public bool EnableDataConstraintChecksOnCompletion { get; set; } = true;
8281

83-
public MaterializeDataContext(SqlTransaction sqlTransaction, MaterializationTableInfo[] materializationTables, ISqlBulkHelpersConfig bulkHelpersConfig)
82+
public MaterializeDataContext(MaterializationTableInfo[] materializationTables, ISqlBulkHelpersConfig bulkHelpersConfig)
8483
{
85-
SqlTransaction = sqlTransaction.AssertArgumentIsNotNull(nameof(sqlTransaction));
8684
Tables = materializationTables.AssertArgumentIsNotNull(nameof(materializationTables));
8785
BulkHelpersConfig = bulkHelpersConfig.AssertArgumentIsNotNull(nameof(bulkHelpersConfig));
8886
TableLookupByFullyQualifiedName = Tables.ToLookup(t => t.LiveTable.FullyQualifiedTableName, StringComparer.OrdinalIgnoreCase);
8987
TableLookupByOriginalName = Tables.ToLookup(t => t.OriginalTableName, StringComparer.OrdinalIgnoreCase);
9088
}
9189

92-
internal async Task HandleNonTransactionTasksBeforeMaterialization()
90+
internal async Task HandleParallelConnectionTasksBeforeMaterialization()
9391
{
9492
//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.)
9593
//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
@@ -118,7 +116,7 @@ await tablesWithFullTextIndexes.ForEachAsync(BulkHelpersConfig.MaxConcurrentConn
118116
/// occurs during the Finish Materialization process!!!
119117
/// </summary>
120118
/// <returns></returns>
121-
internal async Task HandleNonTransactionTasksAfterMaterialization()
119+
internal async Task HandleParallelConnectionTasksAfterMaterialization()
122120
{
123121
if (TablesWithFullTextIndexesRemoved.Any())
124122
{
@@ -134,7 +132,7 @@ await TablesWithFullTextIndexesRemoved.ForEachAsync(BulkHelpersConfig.MaxConcurr
134132
}
135133
}
136134

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

217-
//var timeoutConvertedToMinutes = Math.Max(1, (int)Math.Ceiling((decimal)BulkHelpersConfig.MaterializeDataStructureProcessingTimeoutSeconds / 60));
218-
219-
await SqlTransaction.ExecuteMaterializedDataSqlScriptAsync(
211+
await sqlTransaction.ExecuteMaterializedDataSqlScriptAsync(
220212
switchScriptBuilder,
221213
BulkHelpersConfig.MaterializeDataStructureProcessingTimeoutSeconds
222214
).ConfigureAwait(false);

0 commit comments

Comments
 (0)