public void TestSession42_ReplicateSimple() { // close replica we just created and attach db file to our primary db as "replica" dbReplica.Close(); dbPrimary.AttachDB(dbReplicaPath, "replica"); // verify that "main" has rows in TestTable1 and "replica" currently empty var mainTestTable1Rows = dbPrimary.Query <TestTable1>("Select * FROM main.TestTable1;"); Assert.That(mainTestTable1Rows.Count, Is.GreaterThan(0)); var replicaTestTable1Rows = dbPrimary.Query <TestTable1>("Select * FROM replica.TestTable1;"); Assert.That(replicaTestTable1Rows.Count, Is.EqualTo(0)); // create a session for "main" database Assert.That(dbPrimary.CreateSession("main", out session), Is.EqualTo(SQLite3.Result.OK)); // attach all tables [from "main"] to it Assert.That(SQLiteSession.AttachToTable(session, null), Is.EqualTo(SQLite3.Result.OK)); // Note: we have not enabled watching for changes // validate no changes have occurred Assert.That(SQLiteSession.IsEmptySession(session), Is.True); // see what it would take to make replica.table like main.table #pragma warning disable IDE0018 // Inline variable declaration string errMsg; #pragma warning restore IDE0018 // Inline variable declaration Assert.That(SQLiteSession.AddTableDiffToSession(session, "replica", nameof(TestTable1), out errMsg), Is.EqualTo(SQLite3.Result.OK)); Assert.That(SQLiteSession.AddTableDiffToSession(session, "replica", nameof(TestTable2), out errMsg), Is.EqualTo(SQLite3.Result.OK)); // session should no longer be empty, as tables differ and session should have the diff Assert.That(SQLiteSession.IsEmptySession(session), Is.False); // create change set Assert.That(SQLiteSession.GenerateChangeSet(session, out SQLiteChangeSet changeSet), Is.EqualTo(SQLite3.Result.OK)); // done with our session SQLiteSession.Delete(session); // remove secondary db dbPrimary.DetachDB("replica"); // reopen dbReplica dbReplica = new SQLiteConnection(dbReplicaPath, storeDateTimeAsTicks: true); // validate reopened replica db has no rows replicaTestTable1Rows = dbReplica.Query <TestTable1>("Select * FROM TestTable1;"); Assert.That(replicaTestTable1Rows.Count, Is.EqualTo(0)); // apply change set to dbReplica // should be no conflicts so conflict handler not called Assert.That(dbReplica.ApplySessionChangeSet(changeSet, null, null, null), Is.EqualTo(SQLite3.Result.OK)); // validate has contents we expect replicaTestTable1Rows = dbReplica.Query <TestTable1>("Select * FROM TestTable1;"); Assert.That(replicaTestTable1Rows.Count, Is.GreaterThan(0)); // generate inverse change set Assert.That(SQLiteSession.InvertChangeSet(changeSet, out SQLiteChangeSet inverseChangeSet), Is.EqualTo(SQLite3.Result.OK)); using (inverseChangeSet) { // apply the inverse Assert.That(dbReplica.ApplySessionChangeSet(inverseChangeSet, null, null, null), Is.EqualTo(SQLite3.Result.OK)); // validate replica db once again has no rows replicaTestTable1Rows = dbReplica.Query <TestTable1>("Select * FROM TestTable1;"); Assert.That(replicaTestTable1Rows.Count, Is.EqualTo(0)); } // reset CleanupTest(); SetupTest(); // insert differing row to dbReplica with same primary key, i.e. force conflict // add a row to table var newRow = new TestTable1 { pk = sampleData.pk, myString = "test conflict", // <== only conflicting piece of data myInt = sampleData.myInt, myDate = sampleData.myDate, myTable2Object = sampleData.myTable2Object }; Assert.That(dbReplica.Insert(newRow), Is.EqualTo(1)); // apply change set to dbReplica // should now be a conflict so conflict handler is called Assert.That(dbReplica.ApplySessionChangeSet(changeSet, DummyFilterCallback /* null */, SQLiteSession.CallbackReplaceOnConflicts, null /*"my text context"*/), Is.EqualTo(SQLite3.Result.OK)); // valid has contents we expect replicaTestTable1Rows = dbReplica.Query <TestTable1>("Select * FROM TestTable1;"); Assert.That(replicaTestTable1Rows.Count, Is.GreaterThan(0)); // release our change set buffer explicitly changeSet.Dispose(); }