Dotmim.Sync icon indicating copy to clipboard operation
Dotmim.Sync copied to clipboard

Resolving conflicts issues

Open Vextamour opened this issue 2 years ago • 1 comments

I have a WPF application that is always reading from the SQLite databases online or offline. Then anytime they navigate in the app or save anything I'm always making sync back calls through a WebAPI to keep the SQLite data up to date to the cloud Azure SQL Server. The issue I'm having is resolving conflicts in multiple scenarios below. Ultimately, I think I'm seeking help on how to resolve conflicts and chose what data to update or insert and sync back to the server. I've read documentation but I'm just not getting it to function properly. _At this point I'm not sure if it's allowed but I'd even be happy to pay for some 1:1 time because I need to get past this hold-up quickly. I've been scavenging through Issues and Discussions on here trying to find answers to no avail. I'm on DotMimSync version 0.9.4. Thank you kindly to anyone who can help me 🙏 ! Copied from discussions over to issues.

One scenario is a basic ComputerA input data and ComputerB syncs up to the cloud. However, if I edit a row of data on ComputerB it raises a conflict on the client but never updates the cloud server. I've tried the two sync trick with no consistent luck (also I don't want to specify every single column by name) and attached my TWO SYNC code to say take the client edit over the server (code from local application below). If I step through the code I can see in LocalRow a value change. Then I see it update the RemoteRow value change but then it just never makes it to the server. Later down the road I would like to prompt the user asking which version of data they want but for now I need to get this just syncing at least.

Second scenario there are two computers running the application. ComputerA inserts or updates data then syncs up to the cloud while the person on ComputerB is still filling out an interface. Then ComputerB adds a row but it raises a conflict because the server says the row doesn't exist so it inserts into the SQLite database syncs up to the server and since it doesn't exist there it gets removed instantly out of local database.

                string clientDBConnectionString = Globals.SQLLiteConnectionString;
                string baseUrl = ConfigurationManager.AppSettings["BaseURL"];

                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Globals.Auth0Token.Replace("Bearer ", ""));

                // Adding the HttpClient instance to the web client orchestrator
                var serverOrchestrator = new WebClientOrchestrator($"{baseUrl}api/sync", client: httpClient);

                //var serverOrchestrator = new WebClientOrchestrator("https://localhost:44368/api/sync"); //Uncomment this if you're trying to test the API sync locally
                var clientProvider = new SqliteSyncProvider(clientDBConnectionString);

                var options = new SyncOptions { ConflictResolutionPolicy = ConflictResolutionPolicy.ServerWins };
                
                var agent = new SyncAgent(clientProvider, serverOrchestrator, options);

                var localOrchestrator = agent.LocalOrchestrator;
                var remoteOrchestrator = agent.RemoteOrchestrator;

                try
                {

                    agent.LocalOrchestrator.OnApplyChangesFailed(acf =>
                    {
                        var localRow = acf.Conflict.LocalRow; //Local machine SQLite
                        var remoteRow = acf.Conflict.RemoteRow; //Azure SQL Server

                        //I don't want to have to call each row by name like this. I'd rather call it dynamically in a loop of sorts.
                        //Also in the future I'd like the user to pick but for now just trying to get the client to override what's going to the cloud server.
                        remoteRow["WellNumber"] = localRow["WellNumber"];

                        //I see the remote row updated the WellNumber based off the SQLite local row. 

                        //acf.FinalRow = localRow; /** TRIED FORCING THE FINAL ROW TO LOCAL ROW DIDN'T WORK EITHER**/
                        acf.SenderScopeId = null;
                    });

                    var results = await agent.SynchronizeAsync();

                        MessageBox.Show($"Sync duration: {results.CompleteTime.Subtract(results.StartTime).TotalSeconds}\n" +
                        $"Changes: {results.TotalChangesUploaded}\n" +
                        $"Downloaded: {results.TotalChangesDownloaded}\n" +
                        $"Applied: {results.TotalChangesApplied}\n" +
                        $"Conflicts: {results.TotalResolvedConflicts}");

                    results = await agent.SynchronizeAsync();

                    MessageBox.Show($"Sync duration: {results.CompleteTime.Subtract(results.StartTime).TotalSeconds}\n" +
                                    $"Changes: {results.TotalChangesUploaded}\n" +
                                    $"Downloaded: {results.TotalChangesDownloaded}\n" +
                                    $"Applied: {results.TotalChangesApplied}\n" +
                                    $"Conflicts: {results.TotalResolvedConflicts}");

Vextamour avatar Apr 29 '22 04:04 Vextamour

@Vextamour Sorry for the delay

Do you still have issues regarding conflicts resolution ?

Mimetis avatar Sep 20 '22 10:09 Mimetis