예제 #1
0
    private static async Task CreateSnapshotAsync()
    {
        // Create 2 Sql Sync providers
        var serverProvider     = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(serverDbName));
        var remoteOrchestrator = new RemoteOrchestrator(serverProvider);

        // specific Setup with only 2 tables, and one filtered
        var setup = new SyncSetup(allTables);

        // snapshot directory
        var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Snapshots");


        await remoteOrchestrator.CreateSnapshotAsync(new SyncContext(), setup, directory, 500, CancellationToken.None);

        // client provider
        var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName));

        // Insert a value after snapshot created
        using (var c = serverProvider.CreateConnection())
        {
            var command = c.CreateCommand();
            command.CommandText = "INSERT INTO [dbo].[ProductCategory] ([Name]) VALUES ('Bikes revolution');";
            c.Open();
            command.ExecuteNonQuery();
            c.Close();
        }

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

        var syncOptions = new SyncOptions {
            SnapshotsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Snapshots")
        };

        // Setting the snapshots directory for client
        agent.Options.SnapshotsDirectory = directory;

        // Using the Progress pattern to handle progession during the synchronization
        var progress = new SynchronousProgress <ProgressArgs>(s =>
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}");
            Console.ResetColor();
        });

        var remoteProgress = new SynchronousProgress <ProgressArgs>(s =>
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}");
            Console.ResetColor();
        });


        //// Launch the sync process
        //if (!agent.Parameters.Contains("City"))
        //    agent.Parameters.Add("City", "Toronto");

        //if (!agent.Parameters.Contains("postal"))
        //    agent.Parameters.Add("postal", "NULL");



        do
        {
            Console.Clear();
            Console.WriteLine("Sync Start");
            try
            {
                var s1 = await agent.SynchronizeAsync(progress);

                Console.WriteLine(s1);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        } while (Console.ReadKey().Key != ConsoleKey.Escape);

        Console.WriteLine("End");
    }
 public SqlBuilderTrackingTable(SyncTable tableDescription, ParserName tableName, ParserName trackingName, SyncSetup setup)
 {
     this.tableDescription = tableDescription;
     this.setup            = setup;
     this.tableName        = tableName;
     this.trackingName     = trackingName;
     this.sqlDbMetadata    = new NpgsqlDbMetadata();
 }
예제 #3
0
        public SqlBuilderTrigger(SyncTable tableDescription, ParserName tableName, ParserName trackingName, SyncSetup setup, DbConnection connection, DbTransaction transaction = null)
        {
            this.connection  = connection as NpgsqlConnection;
            this.transaction = transaction as NpgsqlTransaction;

            this.tableDescription = tableDescription;
            this.setup            = setup;
            this.tableName        = tableName;
            this.trackingName     = trackingName;
            this.sqlObjectNames   = new NpgsqlObjectNames(this.tableDescription, this.setup);
        }
        public async Task Table_Drop_One_Cancel()
        {
            var dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            var cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            var sqlProvider = new SqlSyncProvider(cs);

            var options = new SyncOptions();
            var setup   = new SyncSetup(new string[] { "SalesLT.Product" });

            // Overwrite existing table with this new one
            var table   = new SyncTable("Product", "SalesLT");
            var colID   = new SyncColumn("ID", typeof(Guid));
            var colName = new SyncColumn("Name", typeof(string));

            table.Columns.Add(colID);
            table.Columns.Add(colName);
            table.Columns.Add("Number", typeof(int));
            table.PrimaryKeys.Add("ID");
            var schema = new SyncSet();

            schema.Tables.Add(table);

            var localOrchestrator = new LocalOrchestrator(sqlProvider, options);

            var scopeInfo = await localOrchestrator.GetClientScopeInfoAsync();

            scopeInfo.Setup  = setup;
            scopeInfo.Schema = schema;
            await localOrchestrator.SaveClientScopeInfoAsync(scopeInfo);

            // Call create a first time to have an existing table
            var isCreated = await localOrchestrator.CreateTableAsync(scopeInfo, table.TableName, table.SchemaName);

            Assert.True(isCreated);

            // Ensuring we have a clean new instance
            localOrchestrator = new LocalOrchestrator(sqlProvider, options);

            var onCreating = false;
            var onCreated  = false;
            var onDropping = false;
            var onDropped  = false;

            localOrchestrator.OnTableCreating(ttca => onCreating = true);
            localOrchestrator.OnTableCreated(ttca => onCreated   = true);
            localOrchestrator.OnTableDropped(ttca => onDropped   = true);

            localOrchestrator.OnTableDropping(ttca =>
            {
                ttca.Cancel = true;
                onDropping  = true;
            });

            var isDropped = await localOrchestrator.DropTableAsync(scopeInfo, table.TableName, table.SchemaName);

            Assert.True(onDropping);

            Assert.False(isDropped);
            Assert.False(onDropped);
            Assert.False(onCreating);
            Assert.False(onCreated);

            using (var c = new SqlConnection(cs))
            {
                await c.OpenAsync().ConfigureAwait(false);

                var stable = await SqlManagementUtils.GetTableAsync(c, null, "Product", "SalesLT").ConfigureAwait(false);

                Assert.Single(stable.Rows);
                c.Close();
            }

            HelperDatabase.DropDatabase(ProviderType.Sql, dbName);
        }
예제 #5
0
        public async Task Trigger_Drop_One_Cancel()
        {
            var dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            var cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            var sqlProvider = new SqlSyncProvider(cs);

            // Create default table
            var ctx = new AdventureWorksContext((dbName, ProviderType.Sql, sqlProvider), true, false);
            await ctx.Database.EnsureCreatedAsync();

            var options = new SyncOptions();
            var setup   = new SyncSetup(new string[] { "SalesLT.Product" });

            var remoteOrchestrator = new RemoteOrchestrator(sqlProvider, options);

            var scopeInfo = await remoteOrchestrator.GetServerScopeInfoAsync(setup);

            var isCreated = await remoteOrchestrator.CreateTriggerAsync(scopeInfo, "Product", "SalesLT", DbTriggerType.Insert);

            Assert.True(isCreated);

            // Ensuring we have a clean new instance
            remoteOrchestrator = new RemoteOrchestrator(sqlProvider, options);

            var onCreating = 0;
            var onCreated  = 0;
            var onDropping = 0;
            var onDropped  = 0;

            remoteOrchestrator.OnTriggerCreating(tca => onCreating++);

            remoteOrchestrator.OnTriggerCreated(tca => onCreated++);
            remoteOrchestrator.OnTriggerDropping(tca =>
            {
                tca.Cancel = true;
                onDropping++;
            });
            remoteOrchestrator.OnTriggerDropped(tca => onDropped++);

            var isDropped = await remoteOrchestrator.DropTriggerAsync(scopeInfo, "Product", "SalesLT", DbTriggerType.Insert);

            Assert.False(isDropped);
            Assert.Equal(0, onCreating);
            Assert.Equal(0, onCreated);
            Assert.Equal(1, onDropping);
            Assert.Equal(0, onDropped);

            // Check
            using (var c = new SqlConnection(cs))
            {
                await c.OpenAsync().ConfigureAwait(false);

                var check = await SqlManagementUtils.GetTriggerAsync(c, null, "Product_insert_trigger", "SalesLT").ConfigureAwait(false);

                Assert.Single(check.Rows);
                c.Close();
            }

            HelperDatabase.DropDatabase(ProviderType.Sql, dbName);
        }
예제 #6
0
        public void SyncSetup_Compare_TwoSetup_With_Filters_ShouldBe_Equals()
        {
            SyncSetup setup1 = new SyncSetup(new string[] { "Customer", "Product", "ProductCategory", "Employee" });
            SyncSetup setup2 = new SyncSetup(new string[] { "Customer", "Product", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer", "CompanyName");

            var addressCustomerFilter = new SetupFilter("CustomerAddress");

            addressCustomerFilter.AddParameter("CompanyName", "Customer");
            addressCustomerFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressCustomerFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(addressCustomerFilter);

            var addressFilter = new SetupFilter("Address");

            addressFilter.AddParameter("CompanyName", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(addressFilter);

            var orderHeaderFilter = new SetupFilter("SalesOrderHeader");

            orderHeaderFilter.AddParameter("CompanyName", "Customer");
            orderHeaderFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "CustomerId", "SalesOrderHeader", "CustomerId");
            orderHeaderFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            orderHeaderFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(orderHeaderFilter);

            var orderDetailsFilter = new SetupFilter("SalesOrderDetail");

            orderDetailsFilter.AddParameter("CompanyName", "Customer");
            orderDetailsFilter.AddJoin(Join.Left, "SalesOrderHeader").On("SalesOrderDetail", "SalesOrderID", "SalesOrderHeader", "SalesOrderID");
            orderDetailsFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "CustomerId", "SalesOrderHeader", "CustomerId");
            orderDetailsFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            orderDetailsFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(orderDetailsFilter);

            setup2.Filters.Add("Customer", "CompanyName");

            var addressCustomerFilter2 = new SetupFilter("CustomerAddress");

            addressCustomerFilter2.AddParameter("CompanyName", "Customer");
            addressCustomerFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressCustomerFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(addressCustomerFilter2);

            var addressFilter2 = new SetupFilter("Address");

            addressFilter2.AddParameter("CompanyName", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(addressFilter2);

            var orderHeaderFilter2 = new SetupFilter("SalesOrderHeader");

            orderHeaderFilter2.AddParameter("CompanyName", "Customer");
            orderHeaderFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "CustomerId", "SalesOrderHeader", "CustomerId");
            orderHeaderFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            orderHeaderFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(orderHeaderFilter2);

            var orderDetailsFilter2 = new SetupFilter("SalesOrderDetail");

            orderDetailsFilter2.AddParameter("CompanyName", "Customer");
            orderDetailsFilter2.AddJoin(Join.Left, "SalesOrderHeader").On("SalesOrderDetail", "SalesOrderID", "SalesOrderHeader", "SalesOrderID");
            orderDetailsFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "CustomerId", "SalesOrderHeader", "CustomerId");
            orderDetailsFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            orderDetailsFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(orderDetailsFilter2);


            Assert.True(setup1.EqualsByProperties(setup2));
        }
        public async Task Table_Create_All()
        {
            var dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            var cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            var sqlProvider = new SqlSyncProvider(cs);

            var ctx = new AdventureWorksContext((dbName, ProviderType.Sql, sqlProvider), true, false);
            await ctx.Database.EnsureCreatedAsync();

            var options = new SyncOptions();
            var setup   = new SyncSetup(new string[] { "SalesLT.ProductCategory", "SalesLT.ProductModel", "SalesLT.Product", "Posts" });

            var localOrchestrator  = new LocalOrchestrator(sqlProvider, options);
            var remoteOrchestrator = new RemoteOrchestrator(sqlProvider, options);

            var serverScope = await remoteOrchestrator.GetServerScopeInfoAsync(setup);

            // new empty db
            dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            sqlProvider = new SqlSyncProvider(cs);

            localOrchestrator = new LocalOrchestrator(sqlProvider, options);

            var onCreating = 0;
            var onCreated  = 0;
            var onDropping = 0;
            var onDropped  = 0;

            localOrchestrator.OnTableCreating(ttca => onCreating++);
            localOrchestrator.OnTableCreated(ttca => onCreated++);
            localOrchestrator.OnTableDropping(ttca => onDropping++);
            localOrchestrator.OnTableDropped(ttca => onDropped++);

            var scopeInfo = await localOrchestrator.GetClientScopeInfoAsync();

            scopeInfo.Setup  = serverScope.Setup;
            scopeInfo.Schema = serverScope.Schema;
            await localOrchestrator.SaveClientScopeInfoAsync(scopeInfo);

            await localOrchestrator.CreateTablesAsync(scopeInfo);

            Assert.Equal(4, onCreating);
            Assert.Equal(4, onCreated);
            Assert.Equal(0, onDropping);
            Assert.Equal(0, onDropped);

            onCreating = 0;
            onCreated  = 0;
            onDropping = 0;
            onDropped  = 0;

            await localOrchestrator.CreateTablesAsync(scopeInfo);

            Assert.Equal(0, onCreating);
            Assert.Equal(0, onCreated);
            Assert.Equal(0, onDropping);
            Assert.Equal(0, onDropped);

            await localOrchestrator.CreateTablesAsync(scopeInfo, true);

            Assert.Equal(4, onCreating);
            Assert.Equal(4, onCreated);
            Assert.Equal(4, onDropping);
            Assert.Equal(4, onDropped);

            HelperDatabase.DropDatabase(ProviderType.Sql, dbName);
        }
예제 #8
0
 public SqliteTableBuilder(SyncTable tableDescription, ParserName tableName, ParserName trackingTableName, SyncSetup setup) : base(tableDescription, tableName, trackingTableName, setup)
 {
     this.sqliteObjectNames = new SqliteObjectNames(tableDescription, this.TableName, this.TrackingTableName, setup);
     this.sqliteDbMetadata  = new SqliteDbMetadata();
 }
예제 #9
0
 public SqlTableBuilder(SyncTable tableDescription, SyncSetup setup) : base(tableDescription, setup)
 {
     this.ObjectNames = new SqlObjectNames(tableDescription, this.TableName, this.TrackingTableName, setup);
 }
예제 #10
0
    /// <summary>
    /// Test a client syncing through a web api
    /// </summary>
    private static async Task SyncThroughWebApiAsync()
    {
        var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName));

        var handler = new HttpClientHandler {
            AutomaticDecompression = DecompressionMethods.GZip
        };
        var client = new HttpClient(handler)
        {
            Timeout = TimeSpan.FromMinutes(5)
        };

        var proxyClientProvider = new WebClientOrchestrator("http://localhost:52288/api/Sync", null, null, client);



        // ----------------------------------
        // Client side
        // ----------------------------------
        var clientOptions = new SyncOptions
        {
            ScopeInfoTableName = "client_scopeinfo",
            BatchDirectory     = Path.Combine(SyncOptions.GetDefaultUserBatchDiretory(), "sync_client"),
            BatchSize          = 50,
            CleanMetadatas     = true,
            UseBulkOperations  = true,
            UseVerboseErrors   = false,
        };

        var clientSetup = new SyncSetup
        {
            StoredProceduresPrefix = "cli",
            StoredProceduresSuffix = "",
            TrackingTablesPrefix   = "cli",
            TrackingTablesSuffix   = "",
            TriggersPrefix         = "",
            TriggersSuffix         = "",
        };


        var agent = new SyncAgent(clientProvider, proxyClientProvider, clientSetup, clientOptions);

        Console.WriteLine("Press a key to start (be sure web api is running ...)");
        Console.ReadKey();
        do
        {
            Console.Clear();
            Console.WriteLine("Web sync start");
            try
            {
                var progress = new SynchronousProgress <ProgressArgs>(pa => Console.WriteLine($"{pa.Context.SessionId} - {pa.Context.SyncStage}\t {pa.Message}"));

                var s = await agent.SynchronizeAsync(progress);

                Console.WriteLine(s);
            }
            catch (SyncException e)
            {
                Console.WriteLine(e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("UNKNOW EXCEPTION : " + e.Message);
            }


            Console.WriteLine("Sync Ended. Press a key to start again, or Escapte to end");
        } while (Console.ReadKey().Key != ConsoleKey.Escape);

        Console.WriteLine("End");
    }
예제 #11
0
 public override DbSyncAdapter GetSyncAdapter(SyncTable tableDescription, ParserName tableName, ParserName trackingTableName, SyncSetup setup, string scopeName)
 => new SqlSyncAdapter(tableDescription, tableName, trackingTableName, setup, scopeName);
예제 #12
0
    public static async Task SyncHttpThroughKestellAsync()
    {
        // server provider
        // Create 2 Sql Sync providers
        var serverProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(serverDbName));
        var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName));


        // ----------------------------------
        // Client side
        // ----------------------------------
        var clientOptions = new SyncOptions {
            BatchSize = 500
        };

        var proxyClientProvider = new WebClientOrchestrator();

        // ----------------------------------
        // Web Server side
        // ----------------------------------
        var setup = new SyncSetup(allTables)
        {
            ScopeName = "all_tables_scope",
            StoredProceduresPrefix = "s",
            StoredProceduresSuffix = "",
            TrackingTablesPrefix   = "t",
            TrackingTablesSuffix   = "",
            TriggersPrefix         = "",
            TriggersSuffix         = "t"
        };

        // snapshot directory
        var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Snapshots");

        // ----------------------------------
        // Create a snapshot
        // ----------------------------------
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine($"Creating snapshot");
        var remoteOrchestrator = new RemoteOrchestrator(serverProvider);
        await remoteOrchestrator.CreateSnapshotAsync(new SyncContext(), setup, directory, 500, CancellationToken.None);

        Console.WriteLine($"Done.");
        Console.ResetColor();


        // ----------------------------------
        // Insert a value after snapshot created
        // ----------------------------------
        using (var c = serverProvider.CreateConnection())
        {
            var command = c.CreateCommand();
            command.CommandText = "INSERT INTO [dbo].[ProductCategory] ([Name]) VALUES ('Bikes revolution');";
            c.Open();
            command.ExecuteNonQuery();
            c.Close();
        }

        var webServerOptions = new WebServerOptions {
            SnapshotsDirectory = directory
        };

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

        agent.Options = clientOptions;

        var configureServices = new Action <IServiceCollection>(services =>
        {
            services.AddSyncServer <SqlSyncProvider>(serverProvider.ConnectionString, setup, webServerOptions);
        });

        var serverHandler = new RequestDelegate(async context =>
        {
            var webProxyServer = context.RequestServices.GetService(typeof(WebProxyServerOrchestrator)) as WebProxyServerOrchestrator;
            await webProxyServer.HandleRequestAsync(context);
        });

        using (var server = new KestrellTestServer(configureServices))
        {
            var clientHandler = new ResponseDelegate(async(serviceUri) =>
            {
                proxyClientProvider.ServiceUri = serviceUri;
                do
                {
                    Console.Clear();
                    Console.WriteLine("Web sync start");
                    try
                    {
                        var progress = new SynchronousProgress <ProgressArgs>(pa => Console.WriteLine($"{pa.Context.SyncStage}\t {pa.Message}"));
                        var s        = await agent.SynchronizeAsync(progress);
                        Console.WriteLine(s);
                    }
                    catch (SyncException e)
                    {
                        Console.WriteLine(e.ToString());
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("UNKNOW EXCEPTION : " + e.Message);
                    }


                    Console.WriteLine("Sync Ended. Press a key to start again, or Escapte to end");
                } while (Console.ReadKey().Key != ConsoleKey.Escape);
            });
            await server.Run(serverHandler, clientHandler);
        }
    }
예제 #13
0
    /// <summary>
    /// Launch a simple sync, over TCP network, each sql server (client and server are reachable through TCP cp
    /// </summary>
    /// <returns></returns>
    private static async Task SynchronizeAsync()
    {
        // Create 2 Sql Sync providers
        var serverProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(serverDbName));
        //var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName));
        var clientProvider = new SqliteSyncProvider("clientX.db");

        //var setup = new SyncSetup(new string[] { "Address", "Customer", "CustomerAddress", "SalesOrderHeader", "SalesOrderDetail" });
        var setup = new SyncSetup(allTables);

        setup.Filters.Add("Customer", "CompanyName");

        var addressCustomerFilter = new SetupFilter("CustomerAddress");

        addressCustomerFilter.AddParameter("CompanyName", "Customer");
        addressCustomerFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
        addressCustomerFilter.AddWhere("CompanyName", "Customer", "CompanyName");
        setup.Filters.Add(addressCustomerFilter);

        var addressFilter = new SetupFilter("Address");

        addressFilter.AddParameter("CompanyName", "Customer");
        addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
        addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
        addressFilter.AddWhere("CompanyName", "Customer", "CompanyName");
        setup.Filters.Add(addressFilter);

        var orderHeaderFilter = new SetupFilter("SalesOrderHeader");

        orderHeaderFilter.AddParameter("CompanyName", "Customer");
        orderHeaderFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "CustomerId", "SalesOrderHeader", "CustomerId");
        orderHeaderFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
        orderHeaderFilter.AddWhere("CompanyName", "Customer", "CompanyName");
        setup.Filters.Add(orderHeaderFilter);

        var orderDetailsFilter = new SetupFilter("SalesOrderDetail");

        orderDetailsFilter.AddParameter("CompanyName", "Customer");
        orderDetailsFilter.AddJoin(Join.Left, "SalesOrderHeader").On("SalesOrderDetail", "SalesOrderID", "SalesOrderHeader", "SalesOrderID");
        orderDetailsFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "CustomerId", "SalesOrderHeader", "CustomerId");
        orderDetailsFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
        orderDetailsFilter.AddWhere("CompanyName", "Customer", "CompanyName");
        setup.Filters.Add(orderDetailsFilter);


        // Add pref suf
        setup.StoredProceduresPrefix = "s";
        setup.StoredProceduresSuffix = "";
        setup.TrackingTablesPrefix   = "t";
        setup.TrackingTablesSuffix   = "";

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

        // Using the Progress pattern to handle progession during the synchronization
        var progress = new SynchronousProgress <ProgressArgs>(s =>
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}");
            Console.ResetColor();
        });

        var remoteProgress = new SynchronousProgress <ProgressArgs>(s =>
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}");
            Console.ResetColor();
        });

        agent.AddRemoteProgress(remoteProgress);

        //agent.Options.BatchDirectory = Path.Combine(SyncOptions.GetDefaultUserBatchDiretory(), "sync");
        agent.Options.BatchSize         = 1000;
        agent.Options.CleanMetadatas    = true;
        agent.Options.UseBulkOperations = false;
        agent.Options.DisableConstraintsOnApplyChanges = false;
        agent.Options.ConflictResolutionPolicy         = ConflictResolutionPolicy.ClientWins;
        //agent.Options.UseVerboseErrors = false;
        //agent.Options.ScopeInfoTableName = "tscopeinfo";

        var myRijndael = new RijndaelManaged();

        myRijndael.GenerateKey();
        myRijndael.GenerateIV();

        //agent.RemoteOrchestrator.OnSerializingSet(ssa =>
        //{
        //    // Create an encryptor to perform the stream transform.
        //    var encryptor = myRijndael.CreateEncryptor(myRijndael.Key, myRijndael.IV);

        //    using (var msEncrypt = new MemoryStream())
        //    {
        //        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        //        {
        //            using (var swEncrypt = new StreamWriter(csEncrypt))
        //            {
        //                //Write all data to the stream.
        //                var strSet = JsonConvert.SerializeObject(ssa.Set);
        //                swEncrypt.Write(strSet);
        //            }
        //            ssa.Data = msEncrypt.ToArray();
        //        }
        //    }
        //});

        //agent.OnApplyChangesFailed(acf =>
        //{
        //    // Check conflict is correctly set
        //    var localRow = acf.Conflict.LocalRow;
        //    var remoteRow = acf.Conflict.RemoteRow;

        //    // Merge row
        //    acf.Resolution = ConflictResolution.MergeRow;

        //    acf.FinalRow["Name"] = "Prout";

        //});

        do
        {
            Console.Clear();
            Console.WriteLine("Sync Start");
            try
            {
                // Launch the sync process
                if (!agent.Parameters.Contains("CompanyName"))
                {
                    agent.Parameters.Add("CompanyName", "Professional Sales and Service");
                }

                //if (!agent.Parameters.Contains("postal"))
                //    agent.Parameters.Add("postal", DBNull.Value);


                var s1 = await agent.SynchronizeAsync(progress);

                // Write results
                Console.WriteLine(s1);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }


            //Console.WriteLine("Sync Ended. Press a key to start again, or Escapte to end");
        } while (Console.ReadKey().Key != ConsoleKey.Escape);

        Console.WriteLine("End");
    }
예제 #14
0
    private static async Task SynchronizeMultiScopesAsync()
    {
        // Create 2 Sql Sync providers
        var serverProvider = new SqlSyncChangeTrackingProvider(DbHelper.GetDatabaseConnectionString(serverDbName));
        var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName));

        // Create 2 tables list (one for each scope)
        string[] productScopeTables   = new string[] { "ProductCategory", "ProductModel", "Product" };
        string[] customersScopeTables = new string[] { "Address", "Customer", "CustomerAddress", "SalesOrderHeader", "SalesOrderDetail" };

        // Create 2 sync setup with named scope
        var setupProducts  = new SyncSetup(productScopeTables, "productScope");
        var setupCustomers = new SyncSetup(customersScopeTables, "customerScope");

        // Create 2 agents, one for each scope
        var agentProducts  = new SyncAgent(clientProvider, serverProvider, setupProducts);
        var agentCustomers = new SyncAgent(clientProvider, serverProvider, setupCustomers);

        // Using the Progress pattern to handle progession during the synchronization
        // We can use the same progress for each agent
        var progress = new SynchronousProgress <ProgressArgs>(s =>
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}");
            Console.ResetColor();
        });

        var remoteProgress = new SynchronousProgress <ProgressArgs>(s =>
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine($"{s.Context.SyncStage}:\t{s.Message}");
            Console.ResetColor();
        });

        // Spying what's going on the server side
        agentProducts.AddRemoteProgress(remoteProgress);
        agentCustomers.AddRemoteProgress(remoteProgress);


        do
        {
            Console.Clear();
            Console.WriteLine("Sync Start");
            try
            {
                Console.WriteLine("Hit 1 for sync Products. Hit 2 for sync customers and sales");
                var k = Console.ReadKey().Key;

                if (k == ConsoleKey.D1)
                {
                    Console.WriteLine("Sync Products:");
                    var s1 = await agentProducts.SynchronizeAsync(progress);

                    Console.WriteLine(s1);
                }
                else
                {
                    Console.WriteLine("Sync Customers and Sales:");
                    var s1 = await agentCustomers.SynchronizeAsync(progress);

                    Console.WriteLine(s1);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        } while (Console.ReadKey().Key != ConsoleKey.Escape);

        Console.WriteLine("End");
    }
예제 #15
0
 /// <summary>
 /// Create table name and tracking name, accordingly to the setup
 /// </summary>
 public abstract (ParserName tableName, ParserName trackingName) GetParsers(SyncTable tableDescription, SyncSetup setup);
예제 #16
0
        public override (ParserName tableName, ParserName trackingName) GetParsers(SyncTable tableDescription, SyncSetup setup)
        {
            var originalTableName = ParserName.Parse(tableDescription);

            var pref = setup.TrackingTablesPrefix;
            var suf  = setup.TrackingTablesSuffix;

            // be sure, at least, we have a suffix if we have empty values.
            // othewise, we have the same name for both table and tracking table
            if (string.IsNullOrEmpty(pref) && string.IsNullOrEmpty(suf))
            {
                suf = "_tracking";
            }

            var trakingTableNameString = $"{pref}{originalTableName.ObjectName}{suf}";

            if (!string.IsNullOrEmpty(originalTableName.SchemaName))
            {
                trakingTableNameString = $"{originalTableName.SchemaName}.{trakingTableNameString}";
            }

            var trackingTableName = ParserName.Parse(trakingTableNameString);

            return(originalTableName, trackingTableName);
        }
예제 #17
0
        public void SyncSetup_Compare_TwoSetup_Properties_ShouldBe_Different()
        {
            var setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            var setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });

            setup1.StoredProceduresPrefix = "sp1";
            setup2.StoredProceduresPrefix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.StoredProceduresPrefix = null;
            setup2.StoredProceduresPrefix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.StoredProceduresSuffix = "sp1";
            setup2.StoredProceduresSuffix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.StoredProceduresSuffix = null;
            setup2.StoredProceduresSuffix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TriggersPrefix = "sp1";
            setup2.TriggersPrefix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TriggersPrefix = "sp1";
            setup2.TriggersPrefix = null;

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TriggersSuffix = "sp1";
            setup2.TriggersSuffix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TriggersSuffix = "sp1";
            setup2.TriggersSuffix = null;

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TrackingTablesPrefix = "sp1";
            setup2.TrackingTablesPrefix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TrackingTablesPrefix = null;
            setup2.TrackingTablesPrefix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TrackingTablesSuffix = "sp1";
            setup2.TrackingTablesSuffix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));

            setup1 = new SyncSetup(new string[] { "Employee", "ProductCategory", "Product" });
            setup2 = new SyncSetup(new string[] { "Product", "ProductCategory", "Employee" });
            setup1.TrackingTablesSuffix = null;
            setup2.TrackingTablesSuffix = "sp";

            Assert.NotEqual(setup1, setup2);
            Assert.False(setup1.Equals(setup2));
        }
        public async Task LocalOrchestrator_Scope()
        {
            var dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            var cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            var sqlProvider = new SqlSyncProvider(cs);
            var ctx         = new AdventureWorksContext((dbName, ProviderType.Sql, sqlProvider), true, false);
            await ctx.Database.EnsureCreatedAsync();

            var scopeName = "scope";

            var options = new SyncOptions();
            var setup   = new SyncSetup(this.Tables);

            var localOrchestrator = new LocalOrchestrator(sqlProvider, options, setup, scopeName);


            var scopeTableCreating = 0;
            var scopeTableCreated  = 0;
            var scopeLoading       = 0;
            var scopeLoaded        = 0;
            var scopeSaving        = 0;
            var scopeSaved         = 0;

            localOrchestrator.OnScopeSaving(ssa =>
            {
                Assert.NotNull(ssa.Command);
                scopeSaving++;
            });

            localOrchestrator.OnScopeSaved(ssa => scopeSaved++);

            localOrchestrator.OnScopeTableCreating(stca =>
            {
                Assert.NotNull(stca.Command);
                scopeTableCreating++;
            });

            localOrchestrator.OnScopeTableCreated(stca =>
            {
                scopeTableCreated++;
            });

            localOrchestrator.OnScopeLoading(args =>
            {
                Assert.NotNull(args.Command);
                Assert.Equal(SyncStage.ScopeLoading, args.Context.SyncStage);
                Assert.Equal(scopeName, args.Context.ScopeName);
                Assert.Equal(scopeName, args.ScopeName);
                Assert.NotNull(args.Connection);
                Assert.NotNull(args.Transaction);
                Assert.Equal(ConnectionState.Open, args.Connection.State);
                Assert.Same(args.Connection, args.Transaction.Connection);
                scopeLoading++;
            });

            localOrchestrator.OnScopeLoaded(args =>
            {
                Assert.Equal(SyncStage.ScopeLoading, args.Context.SyncStage);
                Assert.Equal(scopeName, args.Context.ScopeName);
                Assert.NotNull(args.ScopeInfo);
                Assert.Equal(scopeName, args.ScopeInfo.Name);
                Assert.NotNull(args.Connection);
                Assert.NotNull(args.Transaction);
                scopeLoaded++;
            });

            var localScopeInfo = await localOrchestrator.GetClientScopeAsync();


            Assert.Equal(1, scopeTableCreating);
            Assert.Equal(1, scopeTableCreated);
            Assert.Equal(1, scopeLoading);
            Assert.Equal(1, scopeLoaded);
            Assert.Equal(1, scopeSaving);
            Assert.Equal(1, scopeSaved);

            scopeTableCreating = 0;
            scopeTableCreated  = 0;
            scopeLoading       = 0;
            scopeLoaded        = 0;
            scopeSaving        = 0;
            scopeSaved         = 0;

            localScopeInfo.Version = "2.0";

            await localOrchestrator.SaveClientScopeAsync(localScopeInfo);

            Assert.Equal(0, scopeTableCreating);
            Assert.Equal(0, scopeTableCreated);
            Assert.Equal(0, scopeLoading);
            Assert.Equal(0, scopeLoaded);
            Assert.Equal(1, scopeSaving);
            Assert.Equal(1, scopeSaved);

            HelperDatabase.DropDatabase(ProviderType.Sql, dbName);
        }
예제 #19
0
        public void SyncSetup_Compare_TwoSetup_With_Filters_ShouldBe_Different()
        {
            // Check Setup shoul be differents when tables names count is not same
            SyncSetup setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory" });
            SyncSetup setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            Assert.False(setup1.EqualsByProperties(setup2));

            // Check Setup should be differents when tables names are differents
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee1" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee2" });
            Assert.False(setup1.EqualsByProperties(setup2));


            // Check when Setup Filter names are differente (Customer1 and Customer2)
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer1", "CompanyName");

            var addressFilter = new SetupFilter("Address");

            addressFilter.AddParameter("CompanyName", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(addressFilter);

            setup2.Filters.Add("Customer2", "CompanyName");

            var addressFilter2 = new SetupFilter("Address");

            addressFilter2.AddParameter("CompanyName", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(addressFilter2);

            Assert.False(setup1.EqualsByProperties(setup2));

            // 2) Check when Setup Filter names are differente (Address1 and Address2)
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer", "CompanyName");

            addressFilter = new SetupFilter("Address1");
            addressFilter.AddParameter("CompanyName", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(addressFilter);

            setup2.Filters.Add("Customer", "CompanyName");

            addressFilter2 = new SetupFilter("Address2");
            addressFilter2.AddParameter("CompanyName", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(addressFilter2);

            Assert.False(setup1.EqualsByProperties(setup2));

            // 3) Check when Setup Parameter names are differente (CompanyName1 and CompanyName2)
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer", "CompanyName");

            addressFilter = new SetupFilter("Address");
            addressFilter.AddParameter("CompanyName1", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName", "Customer", "CompanyName1");
            setup1.Filters.Add(addressFilter);

            setup2.Filters.Add("Customer", "CompanyName");

            addressFilter2 = new SetupFilter("Address");
            addressFilter2.AddParameter("CompanyName2", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName", "Customer", "CompanyName2");
            setup2.Filters.Add(addressFilter2);

            Assert.False(setup1.EqualsByProperties(setup2));

            // 4) Check when Setup Joins names are differente (CustomerAddress1 and CustomerAddress2)
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer", "CompanyName");

            addressFilter = new SetupFilter("Address");
            addressFilter.AddParameter("CompanyName", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress1").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            setup1.Filters.Add(addressFilter);

            setup2.Filters.Add("Customer", "CompanyName");

            addressFilter2 = new SetupFilter("Address");
            addressFilter2.AddParameter("CompanyName", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress2").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            setup2.Filters.Add(addressFilter2);

            Assert.False(setup1.EqualsByProperties(setup2));

            // 5) Check when Setup Where names are differente (CompanyName1 and CompanyName2)
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer", "CompanyName");

            addressFilter = new SetupFilter("Address");
            addressFilter.AddParameter("CompanyName", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName1", "Customer", "CompanyName");
            setup1.Filters.Add(addressFilter);

            setup2.Filters.Add("Customer", "CompanyName");

            addressFilter2 = new SetupFilter("Address");
            addressFilter2.AddParameter("CompanyName", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName2", "Customer", "CompanyName");
            setup2.Filters.Add(addressFilter2);

            Assert.False(setup1.EqualsByProperties(setup2));

            // 6) Check CustomWhere differences
            setup1 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });
            setup2 = new SyncSetup(new string[] { "Customer", "Address", "ProductCategory", "Employee" });

            setup1.Filters.Add("Customer", "CompanyName");

            addressFilter = new SetupFilter("Address");
            addressFilter.AddParameter("CompanyName", "Customer");
            addressFilter.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter.AddWhere("CompanyName", "Customer", "CompanyName");
            addressFilter.AddCustomWhere("ID = @ID2");
            setup1.Filters.Add(addressFilter);

            setup2.Filters.Add("Customer", "CompanyName");

            addressFilter2 = new SetupFilter("Address");
            addressFilter2.AddParameter("CompanyName", "Customer");
            addressFilter2.AddJoin(Join.Left, "CustomerAddress").On("CustomerAddress", "AddressId", "Address", "AddressId");
            addressFilter2.AddJoin(Join.Left, "Customer").On("CustomerAddress", "CustomerId", "Customer", "CustomerId");
            addressFilter2.AddWhere("CompanyName", "Customer", "CompanyName");
            addressFilter2.AddCustomWhere("ID = @ID1");
            setup2.Filters.Add(addressFilter2);

            Assert.False(setup1.EqualsByProperties(setup2));
        }
 public SqlChangeTrackingSyncAdapter(SyncTable tableDescription, ParserName tableName, ParserName trackingName, SyncSetup setup, string scopeName)
     : base(tableDescription, tableName, trackingName, setup, scopeName)
 {
 }
        public async Task Table_Create_One()
        {
            var dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            var cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            var sqlProvider = new SqlSyncProvider(cs);

            var options = new SyncOptions();
            var setup   = new SyncSetup(new string[] { "SalesLT.Product" });

            var table   = new SyncTable("Product", "SalesLT");
            var colID   = new SyncColumn("ID", typeof(Guid));
            var colName = new SyncColumn("Name", typeof(string));

            table.Columns.Add(colID);
            table.Columns.Add(colName);
            table.Columns.Add("Number", typeof(int));
            table.PrimaryKeys.Add("ID");

            var schema = new SyncSet();

            schema.Tables.Add(table);

            var localOrchestrator = new LocalOrchestrator(sqlProvider, options);

            var scopeInfo = await localOrchestrator.GetClientScopeInfoAsync();

            scopeInfo.Setup  = setup;
            scopeInfo.Schema = schema;
            await localOrchestrator.SaveClientScopeInfoAsync(scopeInfo);

            var onCreating = false;
            var onCreated  = false;

            localOrchestrator.OnTableCreating(ttca =>
            {
                var addingID              = Environment.NewLine + $"ALTER TABLE {ttca.TableName.Schema().Quoted()} ADD internal_id int identity(1,1)";
                ttca.Command.CommandText += addingID;
                onCreating = true;
            });

            localOrchestrator.OnTableCreated(ttca =>
            {
                onCreated = true;
            });


            var isCreated = await localOrchestrator.CreateTableAsync(scopeInfo, table.TableName, table.SchemaName);

            Assert.True(isCreated);
            Assert.True(onCreating);
            Assert.True(onCreated);


            // Check we have a new column in tracking table
            using (var c = new SqlConnection(cs))
            {
                await c.OpenAsync().ConfigureAwait(false);

                var cols = await SqlManagementUtils.GetColumnsForTableAsync(c, null, "Product", "SalesLT").ConfigureAwait(false);

                Assert.Equal(4, cols.Rows.Count);
                Assert.NotNull(cols.Rows.FirstOrDefault(r => r["name"].ToString() == "internal_id"));
                c.Close();
            }

            HelperDatabase.DropDatabase(ProviderType.Sql, dbName);
        }
예제 #22
0
 public static IServiceCollection AddSyncServer <TProvider>(this IServiceCollection serviceCollection, string connectionString, SyncSetup setup, WebServerOptions options = null) where TProvider : CoreProvider, new()
 => serviceCollection.AddSyncServer(typeof(TProvider), connectionString, setup, options);
예제 #23
0
 /// <summary>
 /// Construct a DbBuilder
 /// </summary>
 public DbTableBuilder(SyncTable tableDescription, ParserName tableName, ParserName trackingTableName, SyncSetup setup)
 {
     this.TableDescription  = tableDescription;
     this.Setup             = setup;
     this.TableName         = tableName;
     this.TrackingTableName = trackingTableName;
 }
예제 #24
0
 public override DbTableBuilder GetTableBuilder(SyncTable tableDescription, SyncSetup setup) => new MyTableSqlBuilder(tableDescription, setup);
예제 #25
0
        public async Task Trigger_Create_One_Overwrite()
        {
            var dbName = HelperDatabase.GetRandomName("tcp_lo_");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbName, true);

            var cs          = HelperDatabase.GetConnectionString(ProviderType.Sql, dbName);
            var sqlProvider = new SqlSyncProvider(cs);

            // Create default table
            var ctx = new AdventureWorksContext((dbName, ProviderType.Sql, sqlProvider), true, false);
            await ctx.Database.EnsureCreatedAsync();

            var options = new SyncOptions();
            var setup   = new SyncSetup(new string[] { "SalesLT.Product" });

            var remoteOrchestrator = new RemoteOrchestrator(sqlProvider, options);

            var scopeInfo = await remoteOrchestrator.GetServerScopeInfoAsync(setup);

            var onCreating = 0;
            var onCreated  = 0;
            var onDropping = 0;
            var onDropped  = 0;

            remoteOrchestrator.OnTriggerCreating(tca => onCreating++);
            remoteOrchestrator.OnTriggerCreated(tca => onCreated++);
            remoteOrchestrator.OnTriggerDropping(tca => onDropping++);
            remoteOrchestrator.OnTriggerDropped(tca => onDropped++);

            var isCreated = await remoteOrchestrator.CreateTriggerAsync(scopeInfo, "Product", "SalesLT", DbTriggerType.Insert);

            Assert.True(isCreated);
            Assert.Equal(1, onCreating);
            Assert.Equal(1, onCreated);
            Assert.Equal(0, onDropping);
            Assert.Equal(0, onDropped);

            onCreating = 0;
            onCreated  = 0;
            onDropping = 0;
            onDropped  = 0;

            isCreated = await remoteOrchestrator.CreateTriggerAsync(scopeInfo, "Product", "SalesLT", DbTriggerType.Insert);

            Assert.False(isCreated);
            Assert.Equal(0, onCreating);
            Assert.Equal(0, onCreated);
            Assert.Equal(0, onDropping);
            Assert.Equal(0, onDropped);

            isCreated = await remoteOrchestrator.CreateTriggerAsync(scopeInfo, "Product", "SalesLT", DbTriggerType.Insert, true);

            Assert.True(isCreated);
            Assert.Equal(1, onCreating);
            Assert.Equal(1, onCreated);
            Assert.Equal(1, onDropping);
            Assert.Equal(1, onDropped);


            HelperDatabase.DropDatabase(ProviderType.Sql, dbName);
        }
예제 #26
0
        /// <summary>
        /// Default ctor. Using default options and schema
        /// </summary>
        /// <param name="provider"></param>
        public WebServerOrchestrator(CoreProvider provider, SyncOptions options, WebServerOptions webServerOptions, SyncSetup setup, IMemoryCache cache = null, string scopeName = SyncOptions.DefaultScopeName)
            : base(provider, options, setup, scopeName)
        {
            this.WebServerOptions = webServerOptions ?? throw new ArgumentNullException(nameof(webServerOptions));

            this.Cache = cache ?? new MemoryCache(new MemoryCacheOptions());
        }
예제 #27
0
        public async Task RemoteOrchestrator_GetChanges_ShouldReturnNewRowsInserted()
        {
            var dbNameSrv = HelperDatabase.GetRandomName("tcp_lo_srv");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbNameSrv, true);

            var dbNameCli = HelperDatabase.GetRandomName("tcp_lo_cli");
            await HelperDatabase.CreateDatabaseAsync(ProviderType.Sql, dbNameCli, true);

            var csServer       = HelperDatabase.GetConnectionString(ProviderType.Sql, dbNameSrv);
            var serverProvider = new SqlSyncProvider(csServer);

            var csClient       = HelperDatabase.GetConnectionString(ProviderType.Sql, dbNameCli);
            var clientProvider = new SqlSyncProvider(csClient);

            await new AdventureWorksContext((dbNameSrv, ProviderType.Sql, serverProvider), true, false).Database.EnsureCreatedAsync();
            await new AdventureWorksContext((dbNameCli, ProviderType.Sql, clientProvider), true, false).Database.EnsureCreatedAsync();

            var scopeName   = "scopesnap1";
            var syncOptions = new SyncOptions();
            var setup       = new SyncSetup();

            // Make a first sync to be sure everything is in place
            var agent = new SyncAgent(clientProvider, serverProvider, this.Tables, scopeName);

            // Making a first sync, will initialize everything we need
            await agent.SynchronizeAsync();

            // Get the orchestrators
            var localOrchestrator  = agent.LocalOrchestrator;
            var remoteOrchestrator = agent.RemoteOrchestrator;

            // Server side : Create a product category and a product
            // Create a productcategory item
            // Create a new product on server
            var productId     = Guid.NewGuid();
            var productName   = HelperDatabase.GetRandomName();
            var productNumber = productName.ToUpperInvariant().Substring(0, 10);

            var productCategoryName = HelperDatabase.GetRandomName();
            var productCategoryId   = productCategoryName.ToUpperInvariant().Substring(0, 6);

            using (var ctx = new AdventureWorksContext((dbNameSrv, ProviderType.Sql, serverProvider)))
            {
                var pc = new ProductCategory {
                    ProductCategoryId = productCategoryId, Name = productCategoryName
                };
                ctx.Add(pc);

                var product = new Product {
                    ProductId = productId, Name = productName, ProductNumber = productNumber
                };
                ctx.Add(product);

                await ctx.SaveChangesAsync();
            }

            // Get client scope
            var clientScope = await localOrchestrator.GetClientScopeAsync();

            // Get changes to be populated to the server
            var changes = await remoteOrchestrator.GetChangesAsync(clientScope);

            Assert.NotNull(changes.ServerBatchInfo);
            Assert.NotNull(changes.ServerChangesSelected);
            Assert.Equal(2, changes.ServerChangesSelected.TableChangesSelected.Count);
            Assert.Contains("Product", changes.ServerChangesSelected.TableChangesSelected.Select(tcs => tcs.TableName).ToList());
            Assert.Contains("ProductCategory", changes.ServerChangesSelected.TableChangesSelected.Select(tcs => tcs.TableName).ToList());

            var productTable   = changes.ServerBatchInfo.InMemoryData.Tables["Product", "SalesLT"];
            var productRowName = productTable.Rows[0]["Name"];

            Assert.Equal(productName, productRowName);

            var productCategoryTable   = changes.ServerBatchInfo.InMemoryData.Tables["ProductCategory", "SalesLT"];
            var productCategoryRowName = productCategoryTable.Rows[0]["Name"];

            Assert.Equal(productCategoryName, productCategoryRowName);
        }
예제 #28
0
 public SqlBuilderTrigger(SyncTable tableDescription, ParserName tableName, ParserName trackingName, SyncSetup setup)
 {
     this.tableDescription = tableDescription;
     this.setup            = setup;
     this.tableName        = tableName;
     this.trackingName     = trackingName;
     this.sqlObjectNames   = new SqlObjectNames(this.tableDescription, tableName, trackingName, this.setup);
 }
예제 #29
0
 public MariaDBDownloadOnlySyncAdapter(SyncTable tableDescription, ParserName tableName, ParserName trackingName, SyncSetup setup, string scopeName, int bulkBatchMaxLinesCount)
     : base(tableDescription, tableName, trackingName, setup, scopeName)
 {
     this.tableName = tableName;
     this.bulkBatchMaxLinesCount = bulkBatchMaxLinesCount;
 }
예제 #30
0
        private static async Task SynchronizeAsync()
        {
            // Database script used for this sample : https://github.com/Mimetis/Dotmim.Sync/blob/master/CreateAdventureWorks.sql

            // Create 2 Sql Sync providers
            // First provider is using the Sql change tracking feature. Don't forget to enable it on your database until running this code !
            // For instance, use this SQL statement on your server database : ALTER DATABASE AdventureWorks  SET CHANGE_TRACKING = ON  (CHANGE_RETENTION = 10 DAYS, AUTO_CLEANUP = ON)
            // Otherwise, if you don't want to use Change Tracking feature, just change 'SqlSyncChangeTrackingProvider' to 'SqlSyncProvider'
            var serverProvider = new SqlSyncChangeTrackingProvider(serverConnectionString);
            var clientProvider = new SqlSyncProvider(clientConnectionString);

            // Tables involved in the sync process:
            var setup = new SyncSetup("ProductCategory", "ProductModel", "Product",
                                      "Address", "Customer", "CustomerAddress", "SalesOrderHeader", "SalesOrderDetail");

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

            agent.Options.BatchSize = 20;

            // Using the IProgress<T> pattern to handle progession dring the synchronization
            // Be careful, Progress<T> is not synchronous. Use SynchronousProgress<T> instead !
            var progress = new SynchronousProgress <ProgressArgs>(args => Console.WriteLine($"{args.ProgressPercentage:p}:\t{args.Message}"));

            // --------------------------------------------
            // Using Interceptors
            // --------------------------------------------

            // CancellationTokenSource is used to cancel a sync process in the next example
            var cts = new CancellationTokenSource();


            // Intercept a table changes selecting
            // Because the changes are not yet selected, we can easily interrupt the process with the cancellation token
            agent.LocalOrchestrator.OnTableChangesSelecting(args =>
            {
                Console.WriteLine($"-------- Getting changes from table {args.SchemaTable.GetFullName()} ...");

                if (args.SchemaTable.TableName == "Table_That_Should_Not_Be_Sync")
                {
                    cts.Cancel();
                }
            });

            // Row has been selected from datasource.
            // You can change the synrow before the row is serialized on the disk.
            agent.LocalOrchestrator.OnRowsChangesSelected(args =>
            {
                Console.Write(".");
            });

            // Tables changes have been selected
            // we can have all the batch part infos generated
            agent.RemoteOrchestrator.OnTableChangesSelected(tcsa =>
            {
                Console.WriteLine($"Table {tcsa.SchemaTable.GetFullName()}: " +
                                  $"Files generated count:{tcsa.BatchPartInfos.Count()}. " +
                                  $"Rows Count:{tcsa.TableChangesSelected.TotalChanges}");
            });


            // This event is raised when a table is applying some rows, available on the disk
            agent.LocalOrchestrator.OnTableChangesApplying(args =>
            {
                Console.WriteLine($"Table {args.SchemaTable.GetFullName()}: " +
                                  $"Applying changes from {args.BatchPartInfos.Count()} files. " +
                                  $"{args.BatchPartInfos.Sum(bpi => bpi.RowsCount)} rows.");
            });

            // This event is raised for each batch rows (maybe 1 or more in each batch)
            // that will be applied on the datasource
            // You can change something to the rows before they are applied here
            agent.LocalOrchestrator.OnRowsChangesApplying(args =>
            {
                foreach (var syncRow in args.SyncRows)
                {
                    Console.Write(".");
                }
            });

            // This event is raised once all rows for a table have been applied
            agent.LocalOrchestrator.OnTableChangesApplied(args =>
            {
                Console.WriteLine();
                Console.WriteLine($"Table applied: ");
            });

            do
            {
                // Launch the sync process
                var s1 = await agent.SynchronizeAsync(SyncOptions.DefaultScopeName, setup, SyncType.Normal, null, cts.Token, progress);

                // Write results
                Console.WriteLine(s1);
            } while (Console.ReadKey().Key != ConsoleKey.Escape);

            Console.WriteLine("End");
        }