Skip to content

Commit

Permalink
trying to change primary keys on the fly
Browse files Browse the repository at this point in the history
  • Loading branch information
Mimetis committed Dec 29, 2021
1 parent d7f4f91 commit c69122b
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Projects/Dotmim.Sync.Core/DbSyncAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public static SyncTable CreateChangesTable(SyncTable syncTable, SyncSet owner =
changesTable.PrimaryKeys.Add(pkey);

// get ordered columns that are mutables and pkeys
var orderedNames = syncTable.GetMutableColumnsWithPrimaryKeys();
var orderedNames = syncTable.GetMutableColumns(false, true);

foreach (var c in orderedNames)
changesTable.Columns.Add(c.Clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ public virtual Task<SyncSet> ProvisionAsync(SyncSet schema = null, bool overwrit
/// Provision the local database based on the orchestrator setup, and the provision enumeration
/// </summary>
/// <param name="provision">Provision enumeration to determine which components to apply</param>
public virtual Task<SyncSet> ProvisionAsync(SyncProvision provision, bool overwrite = false, ScopeInfo clientScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress<ProgressArgs> progress = null)
=> this.ProvisionAsync(new SyncSet(this.Setup), provision, overwrite, clientScopeInfo, connection, transaction, cancellationToken, progress);
public virtual async Task<SyncSet> ProvisionAsync(SyncProvision provision, bool overwrite = false, ScopeInfo clientScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress<ProgressArgs> progress = null)
{
var schema = clientScopeInfo?.Schema != null ? clientScopeInfo.Schema : new SyncSet(this.Setup);

return await this.ProvisionAsync(schema, provision, overwrite, clientScopeInfo, connection, transaction, cancellationToken, progress);
}


/// <summary>
Expand Down Expand Up @@ -70,6 +74,9 @@ public virtual async Task<SyncSet> ProvisionAsync(SyncSet schema, SyncProvision
clientScopeInfo = await this.InternalGetScopeAsync<ScopeInfo>(this.GetContext(), DbScopeType.Client, this.ScopeName, scopeBuilder, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false);
}

if (clientScopeInfo?.Schema != null && schema == null)
schema = clientScopeInfo.Schema;

schema = await InternalProvisionAsync(this.GetContext(), overwrite, schema, this.Setup, provision, clientScopeInfo, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false);

await runner.CommitAsync().ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,23 @@ public virtual async Task<SyncSet> ProvisionAsync(SyncProvision provision, bool
{
try
{

await using var runner = await this.GetConnectionAsync(SyncStage.Provisioning, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
// Check incompatibility with the flags
if (provision.HasFlag(SyncProvision.ClientScope))
throw new InvalidProvisionForRemoteOrchestratorException();

// Get server scope if not supplied
var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName);

if (serverScopeInfo == null)
{
var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName);

var exists = await this.InternalExistsScopeInfoTableAsync(this.GetContext(), DbScopeType.Server, scopeBuilder, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false);
if (exists)
serverScopeInfo = await this.InternalGetScopeAsync<ServerScopeInfo>(this.GetContext(), DbScopeType.Server, this.ScopeName, scopeBuilder, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false);
}

var schema = new SyncSet(this.Setup);

var schema = serverScopeInfo?.Schema != null ? serverScopeInfo?.Schema : new SyncSet(this.Setup);
schema = await InternalProvisionAsync(this.GetContext(), overwrite, schema, this.Setup, provision, serverScopeInfo, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false);

await runner.CommitAsync().ConfigureAwait(false);
Expand Down
16 changes: 8 additions & 8 deletions Projects/Dotmim.Sync.Core/Set/SyncTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,14 @@ public IEnumerable<SyncColumn> GetMutableColumns(bool includeAutoIncrement = tru
/// <summary>
/// Get all columns that can be queried
/// </summary>
public IEnumerable<SyncColumn> GetMutableColumnsWithPrimaryKeys()
{
foreach (var column in this.Columns.OrderBy(c => c.Ordinal))
{
if (!column.IsCompute && !column.IsReadOnly)
yield return column;
}
}
//public IEnumerable<SyncColumn> GetMutableColumnsWithPrimaryKeys()
//{
// foreach (var column in this.Columns.OrderBy(c => c.Ordinal))
// {
// if (!column.IsCompute && !column.IsReadOnly)
// yield return column;
// }
//}

/// <summary>
/// Get all columns that are Primary keys, based on the names we have in PrimariKeys property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ private MySqlCommand CreateUpdateCommand()
var allColumnsValuesString = new StringBuilder();

string empty = string.Empty;
foreach (var mutableColumn in this.TableDescription.GetMutableColumnsWithPrimaryKeys())
foreach (var mutableColumn in this.TableDescription.GetMutableColumns())
{
var mutableColumnName = ParserName.Parse(mutableColumn, "`").Quoted().ToString();
var parameterColumnName = ParserName.Parse(mutableColumn, "`").Unquoted().Normalized().ToString();
Expand Down Expand Up @@ -275,7 +275,7 @@ private MySqlCommand CreateBulkInitializeCommand(int nbLines = 1)
var allColumnsString = new StringBuilder();

string empty = string.Empty;
foreach (var mutableColumn in this.TableDescription.GetMutableColumnsWithPrimaryKeys())
foreach (var mutableColumn in this.TableDescription.GetMutableColumns())
{
var mutableColumnName = ParserName.Parse(mutableColumn, "`").Quoted().ToString();
allColumnsString.Append($"{empty}{mutableColumnName}");
Expand All @@ -291,7 +291,7 @@ private MySqlCommand CreateBulkInitializeCommand(int nbLines = 1)
{
stringBuilder.Append($"{commaValues}(");
empty = "";
foreach (var mutableColumn in this.TableDescription.GetMutableColumnsWithPrimaryKeys())
foreach (var mutableColumn in this.TableDescription.GetMutableColumns())
{
var parameterColumnName = ParserName.Parse(mutableColumn, "`").Unquoted().Normalized().ToString();
stringBuilder.Append($"{empty}@p{i}_{parameterColumnName}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ private MySqlCommand CreateUpdateCommand()
var setUpdateAllColumnsString = new StringBuilder();

string empty = string.Empty;
foreach (var mutableColumn in this.TableDescription.GetMutableColumnsWithPrimaryKeys())
foreach (var mutableColumn in this.TableDescription.GetMutableColumns())
{
var mutableColumnName = ParserName.Parse(mutableColumn, "`").Quoted().ToString();
var parameterColumnName = ParserName.Parse(mutableColumn, "`").Unquoted().Normalized().ToString();
Expand Down
80 changes: 45 additions & 35 deletions Samples/Dotmim.Sync.SampleConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private static async Task Main(string[] args)
//var clientProvider = new SqliteSyncProvider(clientDatabaseName);

//var clientProvider = new SqlSyncChangeTrackingProvider(DBHelper.GetDatabaseConnectionString(clientDbName));
var setup = new SyncSetup(new string[] { "ProductCategory" });
var setup = new SyncSetup(new string[] { "Product" });
//var options = new SyncOptions() { ProgressLevel = SyncProgressLevel.Information };

//setup.Tables["ProductCategory"].Columns.AddRange(new string[] { "ProductCategoryID", "ParentProductCategoryID", "Name" });
Expand Down Expand Up @@ -183,10 +183,54 @@ private static async Task SynchronizeAsync(CoreProvider clientProvider, CoreProv
Console.ResetColor();
});

setup = new SyncSetup(new string[] { "Product" });

// Creating an agent that will handle all the process
var agent = new SyncAgent(clientProvider, serverProvider, options, setup);

// get scope based on the setup
// getting the scope will provision the database
// so we will need to deprovision - provision again
var serverScope = await agent.RemoteOrchestrator.GetServerScopeAsync();

// Optional Create table on client if not exists

await agent.LocalOrchestrator.ProvisionAsync(serverScope.Schema, SyncProvision.Table);

var clientScope = await agent.LocalOrchestrator.GetClientScopeAsync();

// Deprovision the scope because we want to replace it after
await agent.RemoteOrchestrator.DeprovisionAsync(
SyncProvision.StoredProcedures |
SyncProvision.TrackingTable |
SyncProvision.Triggers);

var schema = serverScope.Schema;


// Removing the primary key that is a auto inc column
schema.Tables[0].PrimaryKeys.Clear();

// Removing the primary key as a column as well
schema.Tables[0].Columns.Remove(
serverScope.Schema.Tables[0].Columns.First(c => c.ColumnName == "ProductID"));

// Add the unique identifier as primary key
schema.Tables[0].PrimaryKeys.Add("rowguid");

// affect temporary schema for provisioning
serverScope.Schema = schema;
clientScope.Schema = schema;

// Provision
await agent.RemoteOrchestrator.ProvisionAsync(SyncProvision.StoredProcedures |
SyncProvision.TrackingTable |
SyncProvision.Triggers, true, serverScope);

await agent.LocalOrchestrator.ProvisionAsync(SyncProvision.StoredProcedures |
SyncProvision.TrackingTable |
SyncProvision.Triggers, true, clientScope);


//// This event is raised before selecting the changes for a particular table
//// you still can change the DbCommand generated, if you need to
Expand Down Expand Up @@ -214,41 +258,7 @@ private static async Task SynchronizeAsync(CoreProvider clientProvider, CoreProv
//});


agent.LocalOrchestrator.OnTableChangesSelectedSyncRow(args =>
{
if (args.SyncRow.RowState == DataRowState.Deleted)
args.SyncRow = null;
});

agent.RemoteOrchestrator.OnTableChangesApplyingSyncRows(async args =>
{
if (args.SchemaTable.TableName == "ProductCategory")
{
var cmd = args.Connection.CreateCommand();
cmd.CommandText = "Select count(*) from ProductCategory_tracking where ProductCategoryID = @ProductCategoryID";
cmd.Connection = args.Connection;
cmd.Transaction = args.Transaction;
var p = cmd.CreateParameter();
p.DbType = DbType.Guid;
p.ParameterName = "@ProductCategoryID";
cmd.Parameters.Add(p);

foreach (var row in args.SyncRows.ToArray())
{
if (row.RowState == DataRowState.Modified)
{
cmd.Parameters[0].Value = new Guid(row["ProductCategoryID"].ToString());
var alreadyExists = await cmd.ExecuteScalarAsync();

if ((int)alreadyExists == 1)
{
args.SyncRows.Remove(row);
}
}
}

}
});

//// The table is read. The batch parts infos are generated and already available on disk
//agent.LocalOrchestrator.OnTableChangesSelected(async tcsa =>
Expand Down

0 comments on commit c69122b

Please sign in to comment.