Introduction
This article introduces a compare/synchronize tool written using C#. The control was initially created for the synchronization of two tables from different databases (production and testing databases). However, I noticed that it could be extended for comparison and synchronization of any object types. The demo presented in the article is used for comparing and synchronizing string based key-value pairs.
Design
The control�s structure is presented in the following figure:
The control receives two collections of type CompareCollection
as input:
public void DisplayCollections ( CompareCollection A,
CompareCollection B )
The CompareCollection
implements ICollection
interface and contains objects of type CompareItem
. The CompareItem
class contains the following members:
private object m_sKey;
private object m_sValue;
private object m_sNewKey;
private object m_sNewValue;
private bool m_bWasAdded = false;
private bool m_bWasModified = false;
private bool m_bWasDeleted = false;
private bool m_bIsDifferentKey = false;
private bool m_bIsDifferentValue = false;
private bool m_bIsDummy = false;
private bool m_bIsReadOnly = false;
Key
is an essential member of the class. Key
is used for the placement of an object in a ListBox
. For instance: Two string
objects will be displayed in the same line of both ListBox
es if and only if both of them have the same keys. (In case, items' values are different, lines containing these items will be highlighted.)
Most of the flags are self explanatory except for IsDifferentKey
and IsDifferentValue
. Note that iCompareKey
and iCompareValue
are CompareItem
's virtual
functions and should be overridden for appropriate objects. In this example, both the key and value are casted to the string
type for comparing.
Another virtual
parameter of the class is sDisplayString
which is used for displaying a string
in the ListBox
. Majority of the logic is concentrated in the LineComparatorControl
class. The main functions are:
DoDisplayCollections
: The function places items in the ListBox
: private void DoDisplayCollections (
CompareCollection oLeft, CompareCollection oRight ) {
int iLeftIndex = 0;
int iRightIndex = 0;
int iSyncIndex = 0;
while ( iLeftIndex < oLeft.Count || iRightIndex < oRight.Count ){
int iCompResult = 0;
if ( iLeftIndex == oLeft.Count ) {
iCompResult = 1;
}else if ( iRightIndex == oRight.Count ){
iCompResult = -1;
}else{
iCompResult = oLeft[iLeftIndex].iCompareKey(
oRight[iRightIndex] );
}
if ( iCompResult < 0 ){
oLeft[iLeftIndex].bDifferentKey = true;
LeftListBox.Items.Insert (iSyncIndex, oLeft[iLeftIndex]);
RightListBox.Items.Insert (iSyncIndex,
new CompareItem( true, true, true ) );
iLeftIndex++;
}else if ( iCompResult > 0 ){
oRight[iRightIndex].bDifferentKey = true;
RightListBox.Items.Insert (iSyncIndex,
oRight[iRightIndex] );
LeftListBox.Items.Insert (iSyncIndex,
new CompareItem( true, true, true ) );
iRightIndex++;
}else{
if (oLeft[iLeftIndex].iCompareValue(oRight[iRightIndex]) != 0 ){
oRight[iRightIndex].bDifferentValue = true;
oLeft[iLeftIndex].bDifferentValue = true;
}
RightListBox.Items.Insert ( iSyncIndex,
oRight[iRightIndex] );
LeftListBox.Items.Insert ( iSyncIndex,
oLeft[iLeftIndex] );
iLeftIndex++;
iRightIndex++;
}
iSyncIndex++;
}
}
bExecuteSync
: This function is used for the synchronization of items.
In case of synchronization failure, the function pops up a message box with an error message. In order to check whether synchronization is possible, a virtual
function bIsSynchronizationOk
is used.
private bool bExecuteSync ( CompareItem oFromItem,
CompareItem oToItem,
ref string sErrorMsg ){
if ( oFromItem.bDummy ){
oToItem.bDeleted = true;
}else if ( oToItem.bDummy ){
oToItem.bAdded = true;
oToItem.sNewKey = oFromItem.sKey;
oToItem.sNewValue = oFromItem.sValue;
}else {
oToItem.bModified = true;
oToItem.sNewKey = oFromItem.sKey;
oToItem.sNewValue = oFromItem.sValue;
}
if ( bIsSynchronizationOk ( oToItem, ref sErrorMsg ) ){
if ( !oToItem.bDeleted ){
oToItem.sKey = oToItem.sNewKey;
oToItem.sValue = oToItem.sNewValue;
}
if ( oToItem.bDeleted || oToItem.bAdded ){
oToItem.bDummy = false;
oFromItem.bDummy = false;
}
oToItem.bDifferentKey = false;
oToItem.bDifferentValue = false;
oFromItem.bDifferentKey = false;
oFromItem.bDifferentValue = false;
return true;
}else{
return false;
}
}
One would need to override functions LeftStoreButton_Click
and RightStoreButton_Click
in order to implement your own store logic for changed items.
Hope this article is helpful.
References
In order to highlight lines in the ListBox
, I used the article: A C# ColorListBox.