<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Mahjayar's WebLog. : Sync Services for ADO.NET</title><link>http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx</link><description>Tags: Sync Services for ADO.NET</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>SQL Azure Data Sync – Moving Schema from Compact Database to SQL Azure</title><link>http://blogs.msdn.com/mahjayar/archive/2009/11/18/sql-azure-data-sync-moving-schema-from-compact-database-to-sql-azure.aspx</link><pubDate>Thu, 19 Nov 2009 01:30:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9924973</guid><dc:creator>Mahjayar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9924973.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9924973</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9924973</wfw:comment><description>&lt;P align=justify&gt;&lt;STRONG&gt;Update 12/11&lt;/STRONG&gt;:&amp;nbsp;Fixing a typo in the code as pointed by the commenter.&lt;/P&gt;
&lt;P align=justify&gt;With yesterdays announcement of the Microsoft Sync Framework Power Pack for SQL Azure, we have had questions on how to move sync schema from SQL Compact database up to SQL Azure. The power pack only comes with tools to automate the sync schema setup from SQL Server to SQL Azure (via the SQL Azure Data Sync Tool) and taking SQL Azure data offline to a new compact database (via the VS Add New Item template). There is no UI tool to go from Compact to SQL Azure or even SQL Azure to SQL Server. &lt;/P&gt;
&lt;P align=justify&gt;Just wanted to point out that its quite simple to achieve the above two non UI supported scenarios via code. Attached is the simple code that shows how to move sync schema from Compact to SQL Azure.&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Collections.Generic;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Linq;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Text;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Data.SqlServerCe;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.Synchronization.Data;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.Synchronization.Data.SqlServerCe;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; Microsoft.Synchronization.Data.SqlAzure;
&lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; System.Data.SqlClient;
&lt;SPAN class=kwrd&gt;namespace&lt;/SPAN&gt; ConsoleApplication1
{
    &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Program
    {
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Main(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] args)
        {
            SqlCeConnection conn = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; SqlCeConnection(&lt;SPAN class=str&gt;"c:\temp\abc.sdf"&lt;/SPAN&gt;);
            &lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; (conn)
            {
                conn.Open();
                DbSyncScopeDescription desc = GetDbSyncDescription(conn);

                &lt;SPAN class=rem&gt;//Check and sync enable the Compact database&lt;/SPAN&gt;
                SqlCeSyncScopeProvisioning ceScope = 
                    &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; SqlCeSyncScopeProvisioning(desc);
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!ceScope.ScopeExists(scopeName, conn))
                {
                    ceScope.Apply(conn);
                }

                SqlConnection azConn = 
                    &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; SqlConnection(&lt;SPAN class=str&gt;"YourSqlAzureConnectionString"&lt;/SPAN&gt;);
                &lt;SPAN class=kwrd&gt;using&lt;/SPAN&gt; (azConn)
                {
                    azConn.Open();
                    &lt;SPAN class=rem&gt;//Check and sync enable the SQL Azure database&lt;/SPAN&gt;
                    SqlAzureSyncScopeProvisioning azScope = 
                        &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; SqlAzureSyncScopeProvisioning(desc);
                    &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (!azScope.ScopeExists(scopeName, azConn))
                    {
                        azScope.Apply(azConn);
                    }
                }
            }
        }

        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] tableNames = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] { &lt;SPAN class=str&gt;"Foo"&lt;/SPAN&gt;, &lt;SPAN class=str&gt;"Bar"&lt;/SPAN&gt; };
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; scopeName = &lt;SPAN class=str&gt;"FooBarScope"&lt;/SPAN&gt;;
        &lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; DbSyncScopeDescription GetDbSyncDescription
            (SqlCeConnection conn)
        {
            DbSyncScopeDescription desc = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; DbSyncScopeDescription();

            &lt;SPAN class=rem&gt;/***&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             * Option 1 for generating schema - Iterate through the list &lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             * of tables you need and get description for them&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             */&lt;/SPAN&gt; 
            &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; table &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; tableNames)
            {&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;                desc.Tables.Add(
                    SqlCeSyncDescriptionBuilder.GetDescriptionForTable
                    (&lt;FONT color=#000000&gt;&lt;SPAN class=str&gt;table&lt;/SPAN&gt;, conn));&lt;/FONT&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;            }

            &lt;SPAN class=rem&gt;/***&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             * Option 2 for generating schema - If you already have a &lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             * Compact database provisioned for sync you&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             * could just read the whole scope description from it.&lt;/SPAN&gt;
&lt;SPAN class=rem&gt;             **/&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;// desc = SqlCeSyncDescriptionBuilder.GetDescriptionForScope(&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;// scopeName, conn);&lt;/SPAN&gt;

            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; desc;
        }
    }
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;To move from SQL Azure to SQL Server you just need to replace SqlCeSyncScopeDescription type with SqlSyncScopeDescription. To access the new types under Microsoft.Synchronization.Data.SqlAzure just add a reference to the dll of the same name found under &lt;STRONG&gt;%programfiles%\Microsoft Sync Framework\Power pack For Sql azure November CTP\&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9924973" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Project+Huron/default.aspx">Project Huron</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/SQL+Azure/default.aspx">SQL Azure</category></item><item><title>Announcing Microsoft Sync Framework Power Pack For SQL Azure CTP</title><link>http://blogs.msdn.com/mahjayar/archive/2009/11/17/announcing-microsoft-sync-framework-power-pack-for-sql-azure-ctp.aspx</link><pubDate>Tue, 17 Nov 2009 19:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9923785</guid><dc:creator>Mahjayar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9923785.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9923785</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9923785</wfw:comment><description>&lt;P&gt;PDC 2009 starts today and Ray Ozzie and Bob Muglia kicked off todays keynote presentation. It gives me great pleasure to announce the public availability of the MSF power pack for SQL Azure. Its a CTP and we are really excited to see people download this and provide feedback around the direction we are heading w.r.t providing a synchronization story for SQL Azure. Head over to &lt;A href="http://tinyurl.com/yhn76rr"&gt;&lt;STRONG&gt;http://tinyurl.com/yhn76rr&lt;/STRONG&gt;&lt;/A&gt;&lt;STRONG&gt; &lt;/STRONG&gt;to download the Power pack. &lt;/P&gt;
&lt;P&gt;The power pack provides the following components.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SQL Azure Data Sync Tool for SQL Server -&lt;/STRONG&gt; This is a automated tool to migrate your on premise SQL server data to SQL Azure by setting up a strong synchronization relationship. Kelly Blue Book demonstrated this in the key note when they moved a table from their on premise database to SQL Azure.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SqlAzureSyncProvider &lt;/STRONG&gt;- Power pack also brings in a new dll, named Microsoft.Synchronization.Data.SqlAzure.dll, that contains a brand new provider, SqlAzureProvider, that enables existing database providers to synchronize with SQL Azure. This also has the new SQL Azure specific Sync metadata provisioning API's.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Sql Azure Offline Visual Studio Plug-In - &lt;/STRONG&gt;This adds a new item template for VS 2008 SP1 that enables you to setup offline synchronization relationships with SQL Azure.&lt;/P&gt;
&lt;P&gt;The team has worked really hard to bring this to you and we would love any feedback you got. You can use the email feature here or send email to &lt;STRONG&gt;syncfdbk &lt;/STRONG&gt;at &lt;STRONG&gt;microsoft&lt;/STRONG&gt; dot &lt;STRONG&gt;com &lt;/STRONG&gt;with your feedback.&lt;/P&gt;
&lt;P&gt;We first discussed about Project "Huron" at last year's PDC and with this CTP we have taken the first steps toward the vision of a Data Hub in the sky. We have a more detailed post about this over at our Sync blog. Refer &lt;A href="http://blogs.msdn.com/sync/archive/2009/11/17/announcing-sql-azure-data-sync-november-ctp-available-for-download.aspx"&gt;http://blogs.msdn.com/sync/archive/2009/11/17/announcing-sql-azure-data-sync-november-ctp-available-for-download.aspx&lt;/A&gt;.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Mark Scurell, our lead PM, will be demonstrating this whole end to end walkthrough in his talk on Thursday 11/19 at 3 PM. For more information refer &lt;A href="http://microsoftpdc.com/Sessions/SVC23"&gt;http://microsoftpdc.com/Sessions/SVC23&lt;/A&gt;. He will take you through the process of synchronizing an on-premise database with SQL Azure, generate an offline cache from SQL Azure down to a SQL Server Compact database and move data between the client, SQL Azure and on-premise server all with just &lt;STRONG&gt;one single line of code&lt;/STRONG&gt;. &lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9923785" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Project+Huron/default.aspx">Project Huron</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/SQL+Azure/default.aspx">SQL Azure</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/MSF+Power+Pack+For+Sql+Azure/default.aspx">MSF Power Pack For Sql Azure</category></item><item><title>MSF V2 DeepDive – Batching Directory and Batch Files</title><link>http://blogs.msdn.com/mahjayar/archive/2009/11/16/msf-v2-deepdive-batching-directory-and-batch-files.aspx</link><pubDate>Mon, 16 Nov 2009 22:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9923203</guid><dc:creator>Mahjayar</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9923203.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9923203</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9923203</wfw:comment><description>&lt;P align=justify&gt;This is a continuation from the previous post I did explaining the new memory based batching feature for Database providers in MSF V2. Please refer to that post at &lt;A title="MSF V2 CTP2 Deep Dive – Memory Based Batching" href="http://blogs.msdn.com/mahjayar/archive/2009/09/16/msf-v2-ctp2-deep-dive-memory-based-batching.aspx" mce_href="http://blogs.msdn.com/mahjayar/archive/2009/09/16/msf-v2-ctp2-deep-dive-memory-based-batching.aspx"&gt;MSF V2 CTP2 Deep Dive – Memory Based Batching&lt;/A&gt;. This is probably a good time to mention that the final version of MSF V2 has been released to web and can be downloaded from &lt;A title=http://msdn.microsoft.com/en-us/sync/default.aspx href="http://msdn.microsoft.com/en-us/sync/default.aspx" mce_href="http://msdn.microsoft.com/en-us/sync/default.aspx"&gt;http://msdn.microsoft.com/en-us/sync/default.aspx&lt;/A&gt;.&lt;/P&gt;
&lt;P align=justify&gt;Database providers chunks up changes by spooling changes to the file system. These chunks, or batch files, are later transferred to the remote provider which applies them in the correct order. At any given point the &lt;STRONG&gt;&lt;EM&gt;runtime&lt;/EM&gt;&lt;/STRONG&gt; will be processing at most one batch file. Notice the emphasis on runtime. Any user specified event operating on the DataSet property would result in more than one batch file live in memory. Batches are spooled to the file system by the enumerating provider and the provider uses the &lt;STRONG&gt;RelationalSyncProvider.BatchingDirectory&lt;/STRONG&gt; property on the enumerating provider to detect the base directory to use. For each sync the runtime will create a unique directory inside the base directory. The name of the base directory is of the format &lt;STRONG&gt;Sync_XXXXXXXXXXXX&lt;/STRONG&gt;. The directory name is unique for the two providers currently synchronizing and the name does not change for subsequent syncs. This allows the runtime to detect “failed” synchronization attempts so it can resume from the failed point. More on the “Sync Resume”&amp;nbsp; feature later. Inside that directory the runtime will spool one&amp;nbsp; &lt;STRONG&gt;SyncBatchHeaderFile.sync&lt;/STRONG&gt; file and one or more &lt;STRONG&gt;.batch&lt;/STRONG&gt; files. The &lt;STRONG&gt;.sync&lt;/STRONG&gt; file is the metadata file that contains metadata on the current sync session. It holds some key information such as the Version, MadeWithKnowledge and DestinationKnowledge. The .batch files contain the raw change data that needs to be applied on the destination. The .batch file is just a binary serialized version of the &lt;STRONG&gt;DbSyncBatchInfo&lt;/STRONG&gt; type. The batch info type contains both the actual data and the metadata corresponding to that data. For faster access to the metadata the runtime serializes the metadata separately from the data. Here is the definition of the DbSyncBatchInfo type.&lt;/P&gt;
&lt;DIV class=csharpcode&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;   1:  &lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; DbSyncBatchInfo : IDisposable&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   2:  &lt;/SPAN&gt;    {&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;   3:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; DbSyncBatchInfo();&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   4:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;long&lt;/SPAN&gt; DataCacheSize { get; set; }&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;   5:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; DataSetSurrogate DataSetSurrogate { get; set; }&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   6:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; Id { get; set; }&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;   7:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; IsLastBatch { get; set; }&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   8:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;uint&lt;/SPAN&gt; SequenceNumber { get; set; }&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;   9:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; Version Version { get; set; }&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  10:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Dispose();&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;  11:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;virtual&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Dispose(&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; cleanup);&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  12:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;byte&lt;/SPAN&gt;[] GetLearnedKnowledge();&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;  13:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SetLearnedKnowledge(&lt;SPAN class=kwrd&gt;byte&lt;/SPAN&gt;[] knowledgeBytes);&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  14:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;override&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; ToString();&lt;/PRE&gt;&lt;PRE class=alt&gt;&lt;SPAN class=lnum&gt;  15:  &lt;/SPAN&gt;    }&lt;/PRE&gt;&lt;/DIV&gt;
&lt;STYLE type=text/css&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P align=justify&gt;The actual data is contained in the DataSetSurrogate property while the rest of the properties are just the metadata for that data. Some key metadata items are&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;&lt;STRONG&gt;Version&lt;/STRONG&gt; – Batching version of the provider that generated this batch. This enables the destination runtime to apply versioning rules when consuming batches generated from an older version.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;&lt;STRONG&gt;Id&lt;/STRONG&gt; – Unique id of this batch&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;&lt;STRONG&gt;SequenceNumber&lt;/STRONG&gt; – This is used by the destination to ensure that batches are applied in the same order they were generated in. This will ensure that batch files arriving out of order at the destination are still consumed in the correct sequence.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;&lt;STRONG&gt;DataCacheSize&lt;/STRONG&gt; – Represents the deserialized size of the data.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P align=justify&gt;With the RTM version we exposed this type out to the user. This change was made to accommodate feedback from users that they wanted to override the default BinarySerializer or in some cases completely move off DataSet as a data transfer medium. With this type public, users can now easily deserialize any .batch file and provider their customizations on top of that. Each batch file contains two binary objects. The first one is the actual DbSyncBatchInfo type sans the actual data followed by the serialized version of DataSertSurrogate. Users customizing this part of the runtime should pay attention to the format. I have attached a simple factory class DbSyncBatchInfoFactory.cs that can serialize and deserialize any batch file.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Resuming Sync Session&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P align=justify&gt;I had earlier mentioned that the runtime uses a unique reproducible directory name for storing batch files whenever it enumerates changes for a provider. This is so that the runtime can attempt to restart earlier failed sync session. There are many reasons for sync session abruptions but the most common one users face is transient network disconnections. Flaky network connections is quite a common issue with mobile users. Users would have restart a sync session if their network connectivity gets dropped in between. This meant that they had to download/upload all changes back to the remote server. This also means that the remote Sql Server is wasting precious CPU time enumerating the same changes over and over. &lt;/P&gt;
&lt;P align=justify&gt;To avoid re-enumerating changes the enumerating provider will check to see if any batch files exist prior to spawning a new “Select” query. If any batch files for the current remote provider exists, the runtime will inspect the files to see if it can reuse those files. Several factors are considered to determine batch reusability such as state of enumeration, destination knowledge etc. The runtime uses the metadata from the SyncBatchHeaderFile.sync to check if existing batch files are relevant for the current state of the destination. If it determines that the files are relevant then it will pick up enumeration from where the older sync left off. This means if a table had changes between the first failed sync session and the restart only those changes would be picked up. If the runtime determines that the existing batch files are not relevant (destination got changes from a different peer or one of the batch files is corrupt of missing or the enumeration was incomplete the first time) all batch files are deleted and a fresh enumeration query is launched.&lt;/P&gt;
&lt;P align=justify&gt;This batching directory is usually cleaned up by the runtime after it successfully applies all changes. Users can override this behavior by setting RelationalSyncProvider.CleanupBatchingDirectory property to false. &lt;/P&gt;
&lt;H1&gt;&amp;nbsp;&lt;/H1&gt;
&lt;H1&gt;Batch Files Cleanup In Mid Tier&lt;/H1&gt;
&lt;P align=justify&gt;If in case users are using a mid tier to communicate with Sql Server then you would need a background job that constantly monitors the batching folder to delete any files older than a certain time. This is needed because the runtime cleanup of the batch files happens only on the destination provider after a successful application (to enable sync restart feature). &lt;/P&gt;
&lt;H1&gt;Anti-Virus tools and Batching&lt;/H1&gt;
&lt;P align=justify&gt;One note of caution to users having real time anti-virus scanning tools. Please exclude the batching directory from real time scan so that there is no file contention between the sync runtime and the virus scan runtime.&lt;/P&gt;
&lt;P align=justify&gt;Maheshwar Jayaraman&lt;/P&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8a7b03a6-cc19-48f9-a26b-94adc232efab class=wlWriterEditableSmartContent&gt;Technorati Tags: &lt;A href="http://technorati.com/tags/DbSyncProvider" rel=tag mce_href="http://technorati.com/tags/DbSyncProvider"&gt;DbSyncProvider&lt;/A&gt;,&lt;A href="http://technorati.com/tags/Sync+Framework" rel=tag mce_href="http://technorati.com/tags/Sync+Framework"&gt;Sync Framework&lt;/A&gt;,&lt;A href="http://technorati.com/tags/Sync+Services+For+ADO.NET" rel=tag mce_href="http://technorati.com/tags/Sync+Services+For+ADO.NET"&gt;Sync Services For ADO.NET&lt;/A&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9923203" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/mahjayar/attachment/9923203.ashx" length="1469" type="text/plain" /><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/DbSyncProvider/default.aspx">DbSyncProvider</category></item><item><title>PDC 2009 and Sync related sessions</title><link>http://blogs.msdn.com/mahjayar/archive/2009/11/13/pdc-2009-and-sync-related-sessions.aspx</link><pubDate>Fri, 13 Nov 2009 21:28:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9922252</guid><dc:creator>Mahjayar</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9922252.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9922252</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9922252</wfw:comment><description>&lt;P&gt;PDC 2009 is next week and I wanted to have a quick post on some of the sessions about Microsoft Sync Framework. &lt;/P&gt;
&lt;DIV class=UIShareStage_Title&gt;&lt;SPAN&gt;&lt;A class="UIShareStage_InlineEdit inline_edit" onclick='new InlineEditor(this, "attachment[params][title]", false); return false;'&gt;&lt;STRONG&gt;Using the Microsoft Sync Framework to Connect Apps to the Cloud &lt;/STRONG&gt;&lt;/A&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV class=UIShareStage_Title&gt;&lt;A href="http://microsoftpdc.com/Sessions/SVC23"&gt;http://microsoftpdc.com/Sessions/SVC23&lt;/A&gt;&lt;/DIV&gt;
&lt;DIV class=UIShareStage_Title&gt;&amp;nbsp;- &lt;A class="UIShareStage_InlineEdit inline_edit" onclick='new InlineEditor(this, "attachment[params][summary]", true); return false;'&gt;Come hear how the Microsoft Sync Framework can be used to bridge on-premises data to SQL Azure and Windows Azure storage.&amp;nbsp; Learn to quickly build applications that use the cloud as a data hub for aggregation of enterprise, partner, desktop and device data&lt;/A&gt;.&lt;/DIV&gt;
&lt;DIV class=UIShareStage_Title&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class=UIShareStage_Title&gt;You should hear more about Sync Framework in some of the Sql Azure sessions as well. Will have more details to share after next Tuesday.&lt;/DIV&gt;
&lt;DIV class=UIShareStage_Title&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class=UIShareStage_Title&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV id=c4afdd181722240a416057 class="UIShareStage_ThumbPagerControl UIThumbPagerControl UIThumbPagerControl_First "&gt;
&lt;DIV class=UIThumbPagerControl_Buttons&gt;&lt;A class="UIThumbPagerControl_Button UIThumbPagerControl_Button_Left"&gt;&lt;/A&gt;&lt;A class="UIThumbPagerControl_Button UIThumbPagerControl_Button_Right"&gt;&lt;/A&gt;&lt;/DIV&gt;
&lt;DIV class=UIThumbPagerControl_Text&gt;&lt;LABEL id=label_no_picture for=no_picture&gt;&lt;STRONG&gt;&lt;FONT color=#666666&gt;&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/LABEL&gt;&amp;nbsp;&lt;/DIV&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9922252" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Windows+Azure/default.aspx">Windows Azure</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/SQL+Azure/default.aspx">SQL Azure</category></item><item><title>MSF V2 CTP2 Deep Dive – Memory Based Batching</title><link>http://blogs.msdn.com/mahjayar/archive/2009/09/16/msf-v2-ctp2-deep-dive-memory-based-batching.aspx</link><pubDate>Thu, 17 Sep 2009 02:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9896105</guid><dc:creator>Mahjayar</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9896105.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9896105</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9896105</wfw:comment><description>&lt;P align=justify&gt;Its been quite a while since I posted about MSF v2 CTP2. As promised in my earlier posts I will be doing a series of deep-dive of the new SyncServices features added in MSF V2 CTP2. Today I am starting off with the Batching feature.&lt;/P&gt;
&lt;P align=justify&gt;One of the most common feedback we received with the peer providers shipped for MSF V1 was the inability to sync changes in batches. Customer using DbSyncProvider always complained of OutOfMemory exceptions when synchronizing large data across databases. The MSF workflow did support the notion of batching but the relational peer providers did not take advantage of the feature. &lt;/P&gt;
&lt;H1&gt;Background:&lt;/H1&gt;
&lt;P align=justify&gt;When we decided to support batching we looked back at how the hub-spoke providers supported batching. For the hub-spoke we supported batched download of data from server by modifying the enumeration query to return rows in batches. Even though this solved the issue of OOM with large data it had some inherent limitations. Some of the problems were&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Code has to be hand coded by the user for each sync schema which meant a higher probability of user error.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Batching was not supported for uploads from the clients.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;There was no easy way to estimate the number of batches you would need. The solution computed batch size by dividing the current tickcount with the last sent tick count for any table. This meant that the batch size was fixed even if the table had 0 changes between the last sent and the current time instance. This meant that the SyncAgent would return empty batches.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Batching was based on number of rows which made it harder to predict when data will be too big. &lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;In general usability was hindered as the batching SP was complex and highly involved. The SP became more complex if the anchors were non timestamp based.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P align=justify&gt;One other problem unique to the peer providers was the use of SyncKnowledge to compute the changes that needs to be synchronized. In hub-spoke these were simple timestamp anchors that users used to compute what has changed in a table and each table had its own anchor which did not collide with other tables. In peer providers the SyncKnowledge represents the “knowledge” of all tables for a given Sync scope. Any disparity in what the knowledge represents about a replica and the actual data would mean data will not synchronize and result in data non-convergence in your sync topology. &lt;/P&gt;
&lt;H1&gt;Motivation for Batching:&lt;/H1&gt;
&lt;P align=justify&gt;When we designed batching we wanted to address all the above shortcomings. We also wanted to reduce the probability of user errors when computing batches. The primary notion of batching would be to avoid running out of memory when synchronizing large amounts of data. The most straight forward way to support batching would be to batch by rows. This works for most cases but does the solve the problem mentioned earlier – how does the user compute how many rows can the client handle. A desktop machine might have enough processing power to consume 10,000 rows at a time but a hand held device might only be able to handle 100 rows. Moreover on a desktop the sync session has to share the available memory which meant that on high loads the number of rows that a sync session can handle without going out of memory rapidly declines. &lt;/P&gt;
&lt;P align=justify&gt;The primary goal of the sync developer is to successfully sync data over from one replica to another without running out of memory. Basically the one and only goal of batching is to ensure that incremental progress can be made with the available memory resource on the machine. Since one of the most deterministic resource a developer has control over is the available memory, we decided to design batching around memory usage. The developer would put a limit on the max amount on the size of data being synchronized. This works wonderfully well as it makes batching an on demand operation. If row based batching was used then the system would have to send ‘N’ batches no matter how small the individual rows were of. In the memory based batching if all changes required to send to the destination fits within the max size specified then batching is bypassed.&lt;/P&gt;
&lt;P align=justify&gt;We also wanted to make it support batching for all kinds of relational stores (Sql, Sql CE and any ADO.NET capable database). We wanted to achieve all of this with as little input from the user as possible. We did not want customers to reinvent the wheel around batching logic for every sync application they wrote.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Batching Workflow:&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P align=justify&gt;With the motivations for batching being clear we decided to enable batching via a simple switch on the &lt;STRONG&gt;RelationalSyncProvider&lt;/STRONG&gt;. We added a new property, &lt;STRONG&gt;MemoryDataCacheSize&lt;/STRONG&gt;", which users can set to limit the amount of memory used (in KB) by the synchronizing rows. Data cache limit can be set on both providers and the runtime will use the lower size to ensure that one peer does not send data that cannot be handled by the destination. Sync runtime will revert to batched mode even if one peer has not specified a cache size.&lt;/P&gt;
&lt;H2&gt;Batched Enumeration:&lt;/H2&gt;
&lt;P align=justify&gt;The workflow of batching is quite simple. Destination providers communicate its cache size by returning it to the &lt;STRONG&gt;SyncOrchestrator&lt;/STRONG&gt; in its &lt;STRONG&gt;GetSyncBatchParameters&lt;/STRONG&gt;() call. This in-turn is passed to the enumerating peer in the &lt;STRONG&gt;GetChangeBatch&lt;/STRONG&gt;() call. Here is the simple workflow of the batched enumeration process.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;If batching is enabled then start a background thread that will compute the enumeration.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Runtime starts by querying the list of tables mentioned in the &lt;STRONG&gt;DbSyncAdapters&lt;/STRONG&gt; list.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;For each table it retrieves the ADO.NET &lt;STRONG&gt;DataReader&lt;/STRONG&gt; for its corresponding enum query.&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;For each row, before reading the column values, it computes the size of the row.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;If current_Data_Cache_Size + Next_Row_Size &amp;lt;= (110% * &lt;STRONG&gt;MemoryDataCacheSize&lt;/STRONG&gt;) specified then it reads the row in to memory.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;If pulling in the new row exceeds the specified &lt;STRONG&gt;MemoryDataCacheSize&lt;/STRONG&gt; it spools the current in memory rows to a file. It then cleans up its data cache and continues reading changes.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Batches are spooled in the user specified directory configured on &lt;STRONG&gt;RelationalSyncProvider.BatchingDirectory&lt;/STRONG&gt; property.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;The above steps are repeated till all the tables have been enumerated.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P align=justify&gt;As you can see batch files are spooled to disk only when the data exceeds the memory size specified. If all changes fit in memory then the system reverts back to non batching mode where all changes are sent to destination in memory.&lt;/P&gt;
&lt;P align=justify&gt;The runtime will try to stuff a batch with data as long as the in-memory size of those data does not exceed the specified batch size by 10%. This is to guard against sending many number of under populated batches.&lt;/P&gt;
&lt;P align=justify&gt;There are times when a single row would be greater than 110% of the specified data cache size. In such cases the runtime errors out with an exception message that lists the offending table and the primary key of the row that is too big. Users would need to increase the data cache size to accommodate that row.&lt;/P&gt;
&lt;P align=justify&gt;Since enumeration happens in the background, we employ a prodcuer/consumer model between the main threads &lt;STRONG&gt;GetChangeBatch&lt;/STRONG&gt;() call and the background enumeration thread. The main consumer thread will block till the producer spools a batch (or reverts to non batched mode if all changes fit in memory) and report this batch information to the destination provider.&lt;/P&gt;
&lt;H2&gt;Batched Apply:&lt;/H2&gt;
&lt;P align=justify&gt;Relational providers uses the type &lt;STRONG&gt;DbSyncContext&lt;/STRONG&gt; to communicate changes between the source and the destination providers. With batching we have added three new properties to this type to facilitate working with batches. The three properties added are&lt;/P&gt;
&lt;P&gt;public string BatchFileName&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { get; set; } ==&amp;gt; Points to the actual spooled batch file.&lt;/P&gt;
&lt;P&gt;public string IsLastBatch&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { get; set; }&lt;/P&gt;
&lt;P&gt;public string IsDataBatched&amp;nbsp;&amp;nbsp;&amp;nbsp; { get; set; }&lt;/P&gt;
&lt;P align=justify&gt;When the destination receives a batched &lt;STRONG&gt;DbSyncContext&lt;/STRONG&gt; it will queue the context. It will queue all batches till it receives the last batch at which point it will open a transaction, deserialize each batch, apply its contents and then finally commit the transaction. Destination provider will apply the batches in the same FIFO order it received them from the source provider.&lt;/P&gt;
&lt;H2&gt;Tombstone Application:&lt;/H2&gt;
&lt;P align=justify&gt;Relational providers usually applies changes in the following order. DELETES followed by INSERTS and UPDATES. Order in which these changes are applied is usually dictated by the order in which the users specify their table adapters. The adapter order assumes that related tables (PK/FK) and ordered correctly.&amp;nbsp; For DELETES, the runtime will apply changes in the reverse adapter order to ensure that child table DELETES are applied first before parent table DELETES to avoid RI violations. Since batches are applied in FIFO order its plausible that the current batch may not contain the child table DELETES. Within a given batch the runtime continues to apply DELETES in reverse order. In the case where the child table is not in current batch the runtime will recognize the SQL errors for those tombstones and queue them up for retry. When all batches have been applied, the runtime will revisit this queued up DELETES and retry applying them. At this point all of the parent deletes should succeed as the dependent child entries should have already been applied.&lt;/P&gt;
&lt;P align=justify&gt;Note that batching does not change any runtime logic related to conflicts handing. Batching only governs the number of rows in memory at any given point of time and nothing else. The only thing you have to guard in your &lt;STRONG&gt;ApplyChangeFailed&lt;/STRONG&gt; event handler is the above mentioned case where a PK delete fails.&lt;/P&gt;
&lt;H1&gt;Batching Assumptions:&lt;/H1&gt;
&lt;UL&gt;
&lt;LI&gt;Sync runtime has full Read/Write access to the directory specified in the &lt;STRONG&gt;BatchingDirectory&lt;/STRONG&gt; property. &lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;MemoryDataCacheSize&lt;/STRONG&gt; only applies to the memory used for reading sync rows. It does not guard against overall process memory usage. &lt;/LI&gt;
&lt;LI&gt;Batches are applied in the order they are received by the destination provider. &lt;/LI&gt;&lt;/UL&gt;
&lt;H1&gt;So, Does It Work?&lt;/H1&gt;
&lt;P align=justify&gt;Moment of truth is whether all this batching thingy works and does it prevent process from running out of memory. I coded up a simple scenario which syncs two tables, Orders and OrderDetails, from a Sql server down to a CE client. The schema for the two tables is quite simple.&lt;/P&gt;
&lt;P&gt;//Orders &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; orderid - int, PK &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; orderdate – datetime&lt;/P&gt;
&lt;P align=justify&gt;&lt;BR&gt;//OrderDetails &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; orderdetailsid - id, PK &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; orderid - int &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; product - varchar(max) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; quantity –int&lt;/P&gt;
&lt;P align=justify&gt;I populated the tables with about 25,000 rows each. Each row in OrderDetails is about 8K in size and each row in orders is about 50 bytes in size. The demo computes the max working set of the process for reporting purposes. I did two runs one without batching and one with batching. Here is the comparison between the two runs.&lt;/P&gt;
&lt;TABLE border=0 cellSpacing=0 cellPadding=2 width=375&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=131&gt;&lt;STRONG&gt;Sync Type&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=131&gt;&lt;STRONG&gt;Peak Working Set (MB)&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=111&gt;&lt;STRONG&gt;Memory Use percent&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=140&gt;Non Batched&lt;/TD&gt;
&lt;TD vAlign=top width=137&gt;446&lt;/TD&gt;
&lt;TD vAlign=top width=115&gt;NA&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=142&gt;Batched (1 MB batch Size)&lt;/TD&gt;
&lt;TD vAlign=top width=139&gt;47&lt;/TD&gt;
&lt;TD vAlign=top width=117&gt;10.53&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=142&gt;Batched (5 MB batch Size)&lt;/TD&gt;
&lt;TD vAlign=top width=139&gt;59&lt;/TD&gt;
&lt;TD vAlign=top width=119&gt;13.2&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=141&gt;Batched (10 MB batch Size)&lt;/TD&gt;
&lt;TD vAlign=top width=139&gt;78&lt;/TD&gt;
&lt;TD vAlign=top width=120&gt;17.45&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P align=justify&gt;As you can see that batching uses approximately 10-20% of the non batched memory for the above sample. This is not to be an indication of memory savings for all kinds of schemas. Feel free to try it with your real world schemas and I am sure you will see considerable improvements.&lt;/P&gt;
&lt;P align=justify&gt;Here is the procmon output for the non-batched case. As you can see the memory utilization keeps climbing till all changes are read in memory.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_2.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_thumb.png" width=494 height=666 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Here is the procmon for the same demo when batching is enabled. You can see that the runtime goes to 31 MB initially and then settles in to a nice pattern as files are spooled and then consumed by the destination.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_4.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_4.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_thumb_1.png" width=465 height=626 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/MSFV2CTP2DeepDiveBatching_C4EE/image_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Here is the MSDN doc link for the batching feature. &lt;A href="http://msdn.microsoft.com/en-us/library/dd918908(SQL.105).aspx"&gt;http://msdn.microsoft.com/en-us/library/dd918908(SQL.105).aspx&lt;/A&gt;. &amp;nbsp;Feel free to comment here is you have any specific questions.&lt;/P&gt;
&lt;P&gt;Next- Detailed look at the batch file.&lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9896105" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/DbSyncProvider/default.aspx">DbSyncProvider</category></item><item><title>Announcing Sync Framework 2.0 CTP2</title><link>http://blogs.msdn.com/mahjayar/archive/2009/06/05/announcing-sync-framework-2-0-ctp2.aspx</link><pubDate>Fri, 05 Jun 2009 23:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9701953</guid><dc:creator>Mahjayar</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9701953.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9701953</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9701953</wfw:comment><description>&lt;P&gt;We just released CTP2 of Microsoft Sync Framework V2. Check out the blog entry at &lt;A href="http://blogs.msdn.com/sync/archive/2009/06/04/announcing-sync-framework-2-0-ctp2.aspx"&gt;http://blogs.msdn.com/sync/archive/2009/06/04/announcing-sync-framework-2-0-ctp2.aspx&lt;/A&gt;&amp;nbsp;for details on major new features.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;We have so much to talk about Sync Services for ADO.NET in this release that I cannot fit all of these in one blog. For starters here are the big features we have crammed in to this CTP.&lt;/P&gt;
&lt;P&gt;1. New Sql CE and Sql based peer sync provider - SqlCeSyncProvider and SqlSyncProvider.&lt;/P&gt;
&lt;P&gt;2. New management API's to automatically provision Sql and Sql Server express to sync enable tables.&lt;/P&gt;
&lt;P&gt;3. API's to backup and restore a Sync enabled database with no loss of Sync metadata.&lt;/P&gt;
&lt;P&gt;4. Support for 0 code support for enabling batching in all databases providers (Sql and Sql CE providers) - This one majorly cool feature.&lt;/P&gt;
&lt;P&gt;5. Snapshot initialization for bootstrapping a new Sql CE peer from an existing peer.&lt;/P&gt;
&lt;P&gt;6. Support for shared server sync scopes on Sql server.&lt;/P&gt;
&lt;P&gt;7. Improved sync performance on Sql CE.&lt;/P&gt;
&lt;P&gt;Thats an summary of the major changes that we are making available in this CTP. Each of these features will require a separate blog post and I will do over the course of this weekend.&lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9701953" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/DbSyncProvider/default.aspx">DbSyncProvider</category></item><item><title>Looking for volunteers for Project Huron Early Adopter Program</title><link>http://blogs.msdn.com/mahjayar/archive/2009/04/30/looking-for-volunteers-for-project-huron-early-adopter-program.aspx</link><pubDate>Fri, 01 May 2009 00:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9581378</guid><dc:creator>Mahjayar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9581378.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9581378</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9581378</wfw:comment><description>&lt;P&gt;Ever since we announced Project Huron at PDC last year we have been hard at work trying to scope out the scenarios for our V1 release. Due to resource contstraints we decided to scope out the Access to Cloud publish use case for V1. We instead decided to concentrate more on sharing Sql Server and Sql Server Compact databases via the Data Hub hosted in the sky. Liam, our Project Manager has a &lt;A href="http://blogs.msdn.com/sync/archive/2009/04/29/project-huron-early-adopter-program.aspx" mce_href="http://blogs.msdn.com/sync/archive/2009/04/29/project-huron-early-adopter-program.aspx"&gt;post over &lt;/A&gt;at our official sync blog asking for some early adopter partners. Please reply back using the contact form at &lt;A href="http://blogs.msdn.com/sync/contact.aspx"&gt;http://blogs.msdn.com/sync/contact.aspx&lt;/A&gt;&amp;nbsp;if you would like to be an early adpoter. Head over to the blog post for see some screen mockups of our early Huron Management studio UI.&lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9581378" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Project+Huron/default.aspx">Project Huron</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Windows+Azure/default.aspx">Windows Azure</category></item><item><title>SyncServicesADO.NET Survery</title><link>http://blogs.msdn.com/mahjayar/archive/2009/04/07/syncservicesado-net-survery.aspx</link><pubDate>Wed, 08 Apr 2009 02:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9536976</guid><dc:creator>Mahjayar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9536976.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9536976</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9536976</wfw:comment><description>&lt;P&gt;We are looking for some SyncServices for ADO.NET users (both Hub spoke and peer to peer toplogy) to take a survey and answer questions on how they handle custom conflict resolution and business logic processing. Please head over to &lt;A href="http://blogs.msdn.com/sync/archive/2009/04/07/custom-conflict-resolution-survey.aspx"&gt;http://blogs.msdn.com/sync/archive/2009/04/07/custom-conflict-resolution-survey.aspx&lt;/A&gt;&amp;nbsp;and leave your responses as comments to that post. &lt;/P&gt;
&lt;P&gt;This will go a long way in helping us figure out how best to streamline our event API's.&lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9536976" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/DbSyncProvider/default.aspx">DbSyncProvider</category></item><item><title>DbSyncProvider WCF Based Synchronization– Memory Performance Analysis Of DataSet Binary SerializationFormat Vs DataSet Surrogates</title><link>http://blogs.msdn.com/mahjayar/archive/2009/03/10/dbsyncprovider-wcf-based-synchronizing-memory-performance-analysis-of-dataset-binary-serializationformat-vs-dataset-surrogates.aspx</link><pubDate>Tue, 10 Mar 2009 11:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9468800</guid><dc:creator>Mahjayar</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9468800.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9468800</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9468800</wfw:comment><description>&lt;P align=justify&gt;I had posted &lt;A href="http://blogs.msdn.com/mahjayar/archive/2008/10/01/dbsyncprovider-improving-memory-performance-in-wcf-based-synchronization.aspx" mce_href="http://blogs.msdn.com/mahjayar/archive/2008/10/01/dbsyncprovider-improving-memory-performance-in-wcf-based-synchronization.aspx"&gt;earlier&lt;/A&gt; about the memory performance when using default DataSet serialization behavior vs. using a Surrogate. Users had some questions on how the DataSet surrogate compared with the DataSet’s Remoting SerializationFormat. With .Net Fx 2.0 DataSet shipped support for serializing DataSet in Binary in addition to the default XML format. I decided to do a quick test comparing the serialization memory usage&amp;nbsp; between the two optimizations. Here is a simple table detailing the memory usage.&lt;/P&gt;
&lt;P align=justify&gt;I used a Toshiba Tecra laptop running Windows 7 Beta build with 2GB RAM. The DataSet contains one DataTable which contains one string column. Each column is a 5Mb string. Size is Peak working set. The BinaryFormatter serializes the DataSet in to a MemoryStream.&lt;/P&gt;
&lt;TABLE border=1 cellSpacing=0 cellPadding=2 width=499&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=84&gt;&lt;STRONG&gt;No of Rows&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;&lt;STRONG&gt;BinaryFormat Serialization (MB)&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;&lt;STRONG&gt;Surrogate Serialization (MB)&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=87&gt;1&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;34.1&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;34.5&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=89&gt;5&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;131.6&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;131.39&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=90&gt;10&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;271.1&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;271.39&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=91&gt;48&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;1116.1&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;1118.1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=92&gt;50&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;Out of Memory&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;1024&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top width=93&gt;51&lt;/TD&gt;
&lt;TD vAlign=top width=203&gt;Out Of Memory&lt;/TD&gt;
&lt;TD vAlign=top width=207&gt;Out Of Memory&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P align=justify&gt;As you can see the memory performance is pretty similar to both the options but the Surrogate approach is able to handle slightly more data than the Binary format. The Binary format peaked at 48 rows while the Surrogate approach peaked at 50 rows. I like the Surrogate approach as it gives the users complete control on the way data is serialized and has option for further user defined optimizations. Further the option to pick DataSet Binary serialization format is not available in the Compact framework which means Surrogates might be the only viable option (as opposed to writing a new serializer) for devices. Next I will compare the wire size of the actual serialized data.&lt;/P&gt;
&lt;P align=justify&gt;Here is the link for original Microsoft KB article on the Surrogate approach. &lt;A href="http://support.microsoft.com/kb/829740" mce_href="http://support.microsoft.com/kb/829740"&gt;http://support.microsoft.com/kb/829740&lt;/A&gt;.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9468800" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/WCF+_2800_Indigo_2900_/default.aspx">WCF (Indigo)</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/DbSyncProvider/default.aspx">DbSyncProvider</category></item><item><title>PDC 08 Summary - Project "Huron" and MSF V2 CTP</title><link>http://blogs.msdn.com/mahjayar/archive/2008/11/06/pdc-08-summary-project-huron-and-msf-v2-ctp.aspx</link><pubDate>Thu, 06 Nov 2008 21:46:02 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9050181</guid><dc:creator>Mahjayar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9050181.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9050181</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9050181</wfw:comment><description>&lt;p align="justify"&gt;PDC 08 was last week and I wanted to summarize the PDC sync specific announcements. Hope every one had a chance to catch up on the all the impressive videos. First, Windows 7 looks impressive and I cant wait to dogfood the Beta build. &lt;/p&gt;  &lt;p&gt;As I posted &lt;a href="http://blogs.msdn.com/mahjayar/archive/2008/10/12/pd-2008-sync-framework-sessions.aspx"&gt;earlier&lt;/a&gt;, we had 3 Microsoft Sync Framework related presentations and here are the direct links to the recorded sessions.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://channel9.msdn.com/pdc2008/TL30/"&gt;Microsoft Sync Framework Advances &lt;/a&gt;– Presenter Lev Novik&lt;/p&gt;  &lt;p&gt;&lt;a href="http://channel9.msdn.com/pdc2008/PC44/"&gt;Windows 7: Programming Sync Providers That Work Great with Windows&lt;/a&gt; – Presenter Jason Roberts&lt;/p&gt;  &lt;p&gt;&lt;a href="http://channel9.msdn.com/pdc2008/BB40/"&gt;Sync Framework: Enterprise Data in the Cloud and on Devices &lt;/a&gt;(Presenter: Liam Cavanagh)&lt;/p&gt;  &lt;p align="justify"&gt;I am involved in &lt;a href="http://sqlserviceslabs.net/huron.html" target="_blank"&gt;Project Huron&lt;/a&gt; and wanted to talk briefly about what we discussed at PDC and what’s coming next. Project Huron intends to be a data hub in the cloud enabling data sharing and replication using the Sql Data Services and Microsoft Sync Framework. Here is the full snippet of Project Huron from our &lt;a href="http://blogs.msdn.com/sync"&gt;Sync blog&lt;/a&gt;.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p align="justify"&gt;&lt;b&gt;&lt;a href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/PDC08SummaryProjectHuronandMSFV2CTP_924E/img56_7.jpg"&gt;&lt;img style="border-right-width: 0px; margin: 1px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="img56" border="0" alt="img56" align="left" src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/PDC08SummaryProjectHuronandMSFV2CTP_924E/img56_thumb.jpg" width="244" height="238" /&gt;&lt;/a&gt; Project Codename “Huron”&lt;/b&gt; – Leverage the power of SQL Data Services and Microsoft Sync Framework to build business data hubs in the cloud. Using this cloud based data hub, “Huron” provides a simpler, more convenient and less expensive way to:&lt;/p&gt;    &lt;p&gt;· Publish databases to the cloud along with reports, forms and objects&lt;/p&gt;    &lt;p&gt;· Subscribe to published data and automatically configure the local database for sync&lt;/p&gt;    &lt;p&gt;· Make online changes through SQL Data Services and propagate those changes to subscribed users once they connect&lt;/p&gt;    &lt;p&gt;· Enable scheduled and background synchronization of data changes through SQL Data Services and then on to other subscribed users&lt;/p&gt;    &lt;p&gt;· Backup and restore of database applications to the cloud&lt;/p&gt; &lt;/blockquote&gt;  &lt;p align="justify"&gt;We showed one such scenario of Project Huron at PDC. The PDC demo shows how customers using Access database can scale out and enable collaboration scenarios on the Access database by publishing it to the cloud. Customers interested in sharing or contributing to the data can subscribe to the hosted Access database. All changes are routed and synchronized in a peer to peer fashion through the cloud hub. We also demonstrated the “data hub” nature of the data in the cloud by downloading the same Access data to a Microsoft Compact database with full bi directional sync support. All components showed in the demo were running on live code. We used Microsoft Synchronization Framework V1 to build our AccessProvider, SDSProvider and SqlCESyncProvider. Acess and CE providers run locally on the box while the SDSProvider is running in our sync service running the cloud handling the SDS store. Feedback from PDC is very promising and the Access scale out/collaboration scenario seems to be a very common problem that customers run in to. Infact, we had a couple of guest posts over at the &lt;a href="http://blogs.msdn.com/access" target="_blank"&gt;Access team blog&lt;/a&gt; and feedback from that blog has also been very promising. You can read the entire post at &lt;a title="Announcement- Storing Access apps and data in the cloud" href="http://blogs.msdn.com/access/archive/2008/10/28/storing-access-apps-and-data-in-the-cloud.aspx"&gt;&lt;em&gt;Announcement- Storing Access apps and data in the cloud&lt;/em&gt;&lt;/a&gt; and &lt;a title="Video demos of Huron - Access and the SQL Server Data Services" href="http://blogs.msdn.com/access/archive/2008/10/31/video-demos-of-huron-access-and-the-sql-server-data-services.aspx"&gt;&lt;em&gt;Video demos of Huron - Access and the SQL Server Data Services&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;What’s next for Huron&lt;/strong&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p align="justify"&gt;We are looking for early adopters to participate in project Huron which will start very soon. If you are interested in participating then please send an email to &lt;a href="mailto:DataLabs@Microsoft.com"&gt;DataLabs@Microsoft.com&lt;/a&gt; with “Huron beta” in the subject line. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p align="justify"&gt;We also announced public availability of the MSF v2 CTP which has some interesting new features built in. More info on MSF V2 CTP1 can be found &lt;a href="http://blogs.msdn.com/sync/archive/2008/10/28/annoucing-sync-framework-v2-ctp1.aspx" target="_blank"&gt;here&lt;/a&gt;. We are very excited about Huron and cant wait to share it with early adopters.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9050181" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Project+Huron/default.aspx">Project Huron</category></item><item><title>No Re-release of Microsoft Sync Framework V1</title><link>http://blogs.msdn.com/mahjayar/archive/2008/10/22/no-re-release-of-microsoft-sync-framework-v1.aspx</link><pubDate>Wed, 22 Oct 2008 21:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9011526</guid><dc:creator>Mahjayar</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/9011526.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=9011526</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=9011526</wfw:comment><description>&lt;P&gt;Last week, &lt;A href="http://blogs.zdnet.com/microsoft/?p=1646" mce_href="http://blogs.zdnet.com/microsoft/?p=1646"&gt;Mary Jo Foley&lt;/A&gt; reported that we re-released Microsoft Sync Framework V1 with updated bits. Since I hadn't seen any internal emails on this I pinged my PM to get more details. Yesterday Liam posted an entry&amp;nbsp;in our &lt;A href="http://blogs.msdn.com/sync/archive/2008/10/21/not-an-updated-version-of-microsoft-sync-framework.aspx" mce_href="http://blogs.msdn.com/sync/archive/2008/10/21/not-an-updated-version-of-microsoft-sync-framework.aspx"&gt;Sync blog&lt;/A&gt; explaining&amp;nbsp;the "bump" in the published date. &lt;STRONG&gt;Summary&lt;/STRONG&gt;: We did not update the bits with any features/bug fixes. Apologize for the confusion.&lt;/P&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9011526" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category></item><item><title>PD 2008 – Sync Framework Sessions</title><link>http://blogs.msdn.com/mahjayar/archive/2008/10/12/pd-2008-sync-framework-sessions.aspx</link><pubDate>Sun, 12 Oct 2008 20:11:17 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8996705</guid><dc:creator>Mahjayar</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/8996705.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=8996705</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=8996705</wfw:comment><description>&lt;p&gt;We have 3 sessions planned for PDC. Details of the &lt;a href="https://sessions.microsoftpdc.com/public/sessions.aspx"&gt;sessions&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Microsoft Sync Framework Advances&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Presenter: Lev Novik&lt;/p&gt;  &lt;p&gt;This session shows you how the next version of the Microsoft Sync Framework makes it easier to synchronize distributed copies of data across desktops, devices, services, or anywhere else they may be stored.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Sync Framework: Enterprise Data in the Cloud and on Devices&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Presenter: Liam Cavanagh&lt;/p&gt;  &lt;p&gt;See how synchronization plays a pivotal role in transitioning to a managed cloud environment by creating a central hub of information in the cloud. Using synchronization, organizations can enable more efficient mobile and enterprise-to-enterprise scenarios.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Windows 7: Programming Sync Providers That Work Great with Windows&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Moe Khosravy, Jason Roberts&lt;/p&gt;  &lt;p&gt;Learn how you can enable your application to synchronize with other applications that use the Microsoft Sync Framework. This session covers how to implement sync for contacts and other PIM data, how to package sync providers for distribution and installation, and how to register sync provider for use on Windows.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;All 3 sessions have excellent content and are shaping very well. I have been involved in the second one being presented by Liam Cavanagh. I will discuss more about the work we did after PDC. PDC is mere 2 weeks away. Excited!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8996705" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category></item><item><title>DbSyncProvider: Improving Memory Performance In WCF Based Synchronization</title><link>http://blogs.msdn.com/mahjayar/archive/2008/10/01/dbsyncprovider-improving-memory-performance-in-wcf-based-synchronization.aspx</link><pubDate>Thu, 02 Oct 2008 06:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8972726</guid><dc:creator>Mahjayar</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/8972726.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=8972726</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=8972726</wfw:comment><description>&lt;P align=justify&gt;Users have frequently wanted the ability to remotely synchronize relational nodes in a peer to peer fashion using SyncServices for ADO.NET. We have a &lt;A href="http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3588696&amp;amp;SiteID=1" mce_href="http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3588696&amp;amp;SiteID=1"&gt;sample demonstrating&lt;/A&gt; remote synchronization by using Windows Communication Foundation (WCF). I wanted to use this post to provide an easy way to optimize the performance of this WCF based solution. DbSyncProvider enumerates all changes in a DataSet and this gets applied on the destination provider. The moment the two providers are moved from a local 2-tier model to a remote n-tier model this DataSet has to be serialized and transmitted over the network. DataSet’s are very efficient when the amount of data involved is very small. The moment your data exceeds few hundred rows the amount of memory required to serialize/deserialize this DataSet is quite huge. Further the serialized size of the DataSet on disk is quite big as well. &lt;/P&gt;
&lt;P align=justify&gt;DataSet object is by default serialized in XML format and serializing/deserialzing this XML data creates a lot of transient objects resulting in a spike in your memory usage. When you have enough data in the DataSet, like synchronizing large number of database rows, your app has the potential to go out of memory deserializing it. Infact users of SyncServices for ADO.NET V2 are quite aware of the OutOfMemoryException when they are synchronizing large number of records in the 2-tier model (&lt;STRONG&gt;PS&lt;/STRONG&gt;: Solving this is the highest priority for us in the next release). Using the WCF solution increases the likelihood of this error happening even for mid sized data that fits fine in memory. &lt;/P&gt;
&lt;P align=justify&gt;There is an easy way to optimize this problem and obliviously it requires users to move away from the XML based default DataSet serialization. Since DataSet doesn’t support any other format, the only way is to use a Surrogate to serialize it. Microsoft Knowledge base has a wonderful article detailing this Surrogate and it can be downloaded from &lt;A title=http://support.microsoft.com/kb/829740 href="http://support.microsoft.com/kb/829740" mce_href="http://support.microsoft.com/kb/829740"&gt;http://support.microsoft.com/kb/829740&lt;/A&gt;. &lt;/P&gt;
&lt;P align=justify&gt;Download it and use it in your WCF based Synchronization&amp;nbsp;apps and you should see vast improvement in your memory usage and performance. &lt;/P&gt;
&lt;P align=justify&gt;I wrote a quick sample checking the process peak memory usage during serialization/deserialization of a DataSet. Here are the comparison numbers between default and surrogate serialization.&lt;/P&gt;
&lt;P align=justify&gt;The DataSet contains one DataTable which contains one string column. Each column is a 5Mb string. Size is Peak working set.&lt;/P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width=496 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=87&gt;&lt;STRONG&gt;No of Rows&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=112&gt;&lt;STRONG&gt;Default Serialization&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=82&gt;&lt;STRONG&gt;Default Deserialization&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=74&gt;&lt;STRONG&gt;Surrogate Serialization&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=139&gt;&lt;STRONG&gt;Surrogate Deserialization&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=87&gt;1&lt;/TD&gt;
&lt;TD class="" vAlign=top width=112&gt;&amp;nbsp;41 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=82&gt;&amp;nbsp;41 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=74&gt;&amp;nbsp;36 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=139&gt;&amp;nbsp;19 Mb&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=87&gt;5&lt;/TD&gt;
&lt;TD class="" vAlign=top width=112&gt;&amp;nbsp;184 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=82&gt;&amp;nbsp;165&amp;nbsp;Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=74&gt;&amp;nbsp;61 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=139&gt;&amp;nbsp;60 Mb&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=87&gt;10&lt;/TD&gt;
&lt;TD class="" vAlign=top width=112&gt;&amp;nbsp;298 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=82&gt;&amp;nbsp;320 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=74&gt;&amp;nbsp;112 Mb&lt;/TD&gt;
&lt;TD class="" vAlign=top width=139&gt;&amp;nbsp;111 Mb&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top width=87&gt;50&lt;/TD&gt;
&lt;TD class="" vAlign=top width=112&gt;&amp;nbsp;&lt;FONT style="BACKGROUND-COLOR: #ccff00"&gt;Out Of Memory&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=82&gt;&lt;FONT style="BACKGROUND-COLOR: #ccff00"&gt;NA&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=74&gt;&lt;FONT style="BACKGROUND-COLOR: #ccff00"&gt;&amp;nbsp;524 Mb&lt;/FONT&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top width=139&gt;&lt;FONT style="BACKGROUND-COLOR: #ccff00"&gt;&amp;nbsp;523 Mb&lt;/FONT&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;Point proven :). As you can see for each 5Mb of data added in memory the default serialization takes anywhere from 6-8 times more memory. For 50 rows (approx 250Mb data size in memory) the serialization step itself&amp;nbsp;fails with OOM. &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8972726" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/WCF+_2800_Indigo_2900_/default.aspx">WCF (Indigo)</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category></item><item><title>Announcing the release of Microsoft Sync Framework V1 and Sync Services for ADO.Net V2</title><link>http://blogs.msdn.com/mahjayar/archive/2008/08/06/announcing-the-release-of-microsoft-sync-framework-v1-and-sync-services-for-ado-net-v2.aspx</link><pubDate>Wed, 06 Aug 2008 21:13:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8838366</guid><dc:creator>Mahjayar</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/8838366.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=8838366</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=8838366</wfw:comment><description>&lt;p align="justify"&gt;Microsoft just released SQL Server 2008 and with that we have also released the golden versions of Microsoft Sync Framework V1 and Sync Services for ADO.Net V2. With this release Sync services now is built on top of the Sync Framework and supports peer to peer synchronization in addition to hub-spoke topology.&lt;/p&gt;  &lt;p align="justify"&gt;Our &lt;a href="http://blogs.msdn.com/sync"&gt;Sync blog&lt;/a&gt; has a post detailing all &lt;a href="http://blogs.msdn.com/sync/archive/2008/08/06/top-new-features-in-sync-services-for-ado-net-v2.aspx"&gt;new features&lt;/a&gt; that we have shipped in this release. Check it out.&lt;/p&gt;  &lt;p align="justify"&gt;With this release we also pleased to announce the stand alone availability of the Sync Framework and Sync Services installer. When SQL Server 2008 RC was released the framework and services were part of SQL server installer and we did not provide a standalone installer. Go grab the new bits from &lt;a title="http://www.microsoft.com/downloads/details.aspx?FamilyId=C88BA2D1-CEF3-4149-B301-9B056E7FB1E6&amp;amp;displaylang=en" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C88BA2D1-CEF3-4149-B301-9B056E7FB1E6&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyId=C88BA2D1-CEF3-4149-B301-9B056E7FB1E6&amp;amp;displaylang=en&lt;/a&gt;. Now every one should be able to check out our &lt;a href="http://www.maheshwar.net/projects/Sync/DbSyncProviderSample.zip"&gt;DbSyncProvider hello world sample&lt;/a&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;Happy synchronization.&lt;/p&gt;  &lt;p&gt;Maheshwar Jayaraman&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8838366" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category></item><item><title>Getting started with DbSyncProvider (Peer to Peer Synchronization)</title><link>http://blogs.msdn.com/mahjayar/archive/2008/06/25/getting-started-with-dbsyncprovider-peer-to-peer-synchronization.aspx</link><pubDate>Wed, 25 Jun 2008 10:09:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8651450</guid><dc:creator>Mahjayar</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/mahjayar/comments/8651450.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mahjayar/commentrss.aspx?PostID=8651450</wfw:commentRss><wfw:comment>http://blogs.msdn.com/mahjayar/rsscomments.aspx?PostID=8651450</wfw:comment><description>&lt;P align=justify&gt;[&lt;STRONG&gt;Note&lt;/STRONG&gt;: Source for this sample can be downloaded from &lt;A href="http://www.maheshwar.net/projects/Sync/DbSyncProviderSample.zip" mce_href="http://www.maheshwar.net/projects/Sync/DbSyncProviderSample.zip"&gt;http://www.maheshwar.net/projects/Sync/DbSyncProviderSample.zip&lt;/A&gt;. Just ensure that you modify the connectionstrings in properties\settings file to point to the correct database. This sample is based off the &lt;A class="" href="http://blogs.msdn.com/sync/archive/2008/06/09/announcing-sync-framework-v1-0-rc0-and-sync-services-for-ado-net-v2-0-rc0.aspx" mce_href="http://blogs.msdn.com/sync/archive/2008/06/09/announcing-sync-framework-v1-0-rc0-and-sync-services-for-ado-net-v2-0-rc0.aspx"&gt;RC0 build recently released&lt;/A&gt;.]&lt;/P&gt;
&lt;P align=justify&gt;This post is to be a starting guide for people wanting to use &lt;A href="http://msdn.microsoft.com/en-us/sync/default.aspx" mce_href="http://msdn.microsoft.com/en-us/sync/default.aspx"&gt;Microsoft Sync Framework&lt;/A&gt; to synchronize databases. We are shipping a customized database provider, DbSyncProvider, that lets users synchronize tables in a peer to peer fashion. Note that we also ship a DbServerSyncProvider/DbClientSyncProvider combination in Sync Services For ADO.NET API that synchronizes data between Server and Client in a hub-and-spoke topology. DbSyncProvider will allow hub-and-spoke synchronization (if that is what is required) but the real power lies in the peer to peer synchronization. &lt;/P&gt;
&lt;P align=justify&gt;This post will walk through the steps required to sync an existing table using DbSyncProvider. We will use a simple WinForms application to view/edit and synchronize a Customer table across two DB's. &lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_2.png" target=_blank mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=423 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb.png" width=512 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P align=justify&gt;This post assumes that the table Customer cannot be modified and hence we will use a separate table (DeCoupled Tracking), CustomerMetadata, to track item metadata. To keep our queries simple we will use the default DB metadata column names. I will show at the very end how simple it is to modify the above solution for a table that maintains the metadata in the same table (Coupled Tracking). For sake of simplicity lets approach the database synchronization configuration in these following steps.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV&gt;DbSyncProvider Specifics&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Create Scope Information table&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Add metadata for Customer table&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Configure Source DbSyncProvider&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Specify Synchronization Scope commands&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Configure Destination DbSyncProvider&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Conclusion: Putting it all together&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;H1&gt;Step 1. DbSyncProvider Specifics&lt;/H1&gt;
&lt;P align=justify&gt;A DbSyncProvider represents a set of tables within a database defined by a “scope”that are to be synchronized. It contains information such as the connection string and the synchronization scope name, as well as Knowledge information that is used to determine what information is known by the local peer. Each table that needs to be synchronized from the database needs to be represented by a DbSyncAdapter and should be added to the SyncAdapters collection on the provider. Each DbSyncAdapter will contain SqlCommands for the following tasks.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;Selecting incremental changes that are not in the destination’s knowledge. &lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Performing Inserts/Updates/Deletes from remote peers and updating corresponding metadata.&lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Cleanup tombstone metadata.&lt;/P&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Select a particular row with a given id. &lt;/P&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P align=justify&gt;At the provider level, users need to specify SqlCommands for the following tasks.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Select the current timestamp for the local provider.&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=justify&gt;Select/update Scope info for given scope_name.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P align=justify&gt;With our sample we will see the very basic properties that needs to be configured at the provider/syncadapter level to get started. To keep this demo simple, I am going to refrain from using stored procedures and rather depend on plain vanilla select/insert/delete SQL commands. For this demo we will create two databases SampleDB1 and SampleDB2 and will create two DbSyncProviders to represent them. Create the above mentioned databases.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_8.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_8.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=98 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_3.png" width=184 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_3.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Note: For RC release, DbSyncProviders expects to have snapshot isolation turned on at each database. This also means that this can be used against Sql Server 2005 and higher. So after creating them run the following command in both databases.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_66.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_66.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=26 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_1.png" width=481 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;H1&gt;Step 2. Create Scope Information Table&lt;/H1&gt;
&lt;P align=justify&gt;As I mentioned earlier the provider needs the synchronization scope name and other scope related commands (update/select). Scope represents a set of tables that are involved in a sync session and each scope will need to maintain knowledge (data and tombstone) information for all peers that this scope has synchronized with in the past. We will create a &lt;STRONG&gt;Scope_Info&lt;/STRONG&gt; table to maintain this information. The design for the &lt;STRONG&gt;scope_info&lt;/STRONG&gt; table in &lt;STRONG&gt;SampleDB1&lt;/STRONG&gt; database is as follows.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_16.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_16.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=127 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_7.png" width=418 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_7.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;It contains the scope id, sync knowledge, tombstone knowledge and the last updated timestamp to hold all scope related information. Scope Id is a unique identifier Lets create a new scope 'DbSyncDemo' and use this to synchronize our user tables. Initially it will contain null for DbSyncSession.SyncScopeKnowledge and DbSyncSession.SyncScopeCleanupKnowledge. This will tell the core Sync runtime that this database has not synchronized with any peer.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image13.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image13.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=49 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image13_thumb.png" width=509 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image13_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;We need the scope table in all peers that will be involved in the synchronization session so create the same table in the &lt;STRONG&gt;SampleDb2&lt;/STRONG&gt; database as well.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;: All column names of this table matches the constant values for scope metadata columns in &lt;STRONG&gt;DbSyncSession&lt;/STRONG&gt;. The provider will look for these column names from the result set when selecting or updating scope. &lt;/P&gt;
&lt;H1&gt;Step 3. Add metadata for Customer table&lt;/H1&gt;
&lt;P&gt;Lets take a look at the Customer table. It contains fields for name, age and country of each customer. Design of Customer table is as follows.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_20.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_20.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=126 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_9.png" width=334 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_9.png"&gt;&lt;/A&gt;&amp;nbsp; &lt;/P&gt;
&lt;P align=justify&gt;We use id as the Primary Key for this table. Next we need to create a CustomerMetadata table that will hold row metadata for each row in Customer table. Each row in the table represents an Item in the Sync world and hence our metadata table needs to maintain the modified timestamp, creation id, creation timestamp, update key, update timestamp and tombstone metadata for each corresponding row in Customer table. We will use the PK column ‘id’ from the base table to correlated entries in the metadata table. Once again we will use the constant metadata names from DbSyncSession class to name the columns in this table. Design of CustomerMetadata table is as follows.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_22.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_22.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=165 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_10.png" width=341 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_10.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Next we need to update the metadata table each time a row is inserted/updated/deleted. For that we will add triggers on Customer table. We will create 3 triggers, one each for Insert, Update and Delete. Lets take a look at the insert trigger.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;CREATE TRIGGER [dbo].[customer_insert_trigger] &lt;BR&gt;&amp;nbsp;&amp;nbsp; ON&amp;nbsp; [dbo].[Customer] &lt;BR&gt;&amp;nbsp;&amp;nbsp; For INSERT &lt;BR&gt;AS &lt;BR&gt;BEGIN &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Insert statements for trigger here &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; insert into CustomerMetadata (id, sync_row_is_tombstone,sync_create_peer_key, sync_create_peer_timestamp, sync_update_peer_key, sync_update_peer_timestamp) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; select id, 0,0,@@DBTS+1,0,@@DBTS+1 from inserted &lt;BR&gt;END&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P align=justify&gt;Since in Sync, '0' is the id for the current peer we enter 0 as the create/update key. Similarly we enter 0 for the tombstone column denoting that it is not a tombstone row.&lt;/P&gt;
&lt;P align=justify&gt;The update trigger is much simpler. In case of updated we only need to update the update key (will always be 0 denoting current peer) and update timestamp. &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;CREATE TRIGGER [dbo].[customer_update_trigger] &lt;BR&gt;&amp;nbsp;&amp;nbsp; ON&amp;nbsp; [dbo].[Customer] &lt;BR&gt;&amp;nbsp;&amp;nbsp; For update &lt;BR&gt;AS &lt;BR&gt;BEGIN &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Insert statements for trigger here &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; update meta &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set sync_update_peer_key = 0, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sync_update_peer_timestamp = @@DBTS +1&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; from CustomerMetadata meta join inserted i on&amp;nbsp; i.id = meta.id &lt;BR&gt;END&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Finally the delete trigger will set the tombstone column to 1 (in addition to modifying the update key/timestamp pair).&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;CREATE TRIGGER [dbo].[customer_delete_trigger] &lt;BR&gt;&amp;nbsp;&amp;nbsp; ON&amp;nbsp; [dbo].[Customer] &lt;BR&gt;&amp;nbsp;&amp;nbsp; For delete &lt;BR&gt;AS &lt;BR&gt;BEGIN &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Insert statements for trigger here &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; update meta &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set sync_row_is_tombstone = 1, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sync_update_peer_key = 0, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/EM&gt;&lt;EM&gt;sync_update_peer_timestamp = @@DBTS+1&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; from CustomerMetadata meta join deleted i on i.id = meta.id &lt;BR&gt;END&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P align=justify&gt;Create the above tables, triggers in SampleDb1 and SampleDb2 databases. Next we are ready to configure DbSyncProvider's for each of these endpoints. For starters purpose we will just sync in one direction, i.e SampleDb1 -&amp;gt; SampleDb2. I use this example as opposed to discussing a two way sync as I want to list the specific properties that needs to be set for a "source" vs "destination" provider.&lt;/P&gt;
&lt;H1&gt;&amp;nbsp;&lt;/H1&gt;
&lt;H1&gt;Step 4. Configure Source DbSyncProvider&lt;/H1&gt;
&lt;P align=justify&gt;Lets start by creating a DbSyncProvider object and pass the connection string for SampleDb1. Since we are using Decoupled metadata table we will set the ChangeTracking property on the provider. to ChangeTrackingModel.Decoupled.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_24.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_24.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=60 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_11.png" width=477 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_11.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Next, create a DbSyncAdapter for Customer table. &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_28.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_28.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=38 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_13.png" width=446 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_13.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Each DbSyncAdapter needs to know the list of Id columns whose value it will use to create a unique SyncId for each row metadata. In our case we will add column "Id" to the RowIdColumns collection. Next the only command that this DbSyncAdapter needs to provide is the SelectIncrementalChanges command. This will return the rows that have been modified/added/deleted since the destination provider last sync'd. &lt;/P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image29.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image29.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=144 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image29_thumb.png" width=511 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image29_thumb.png"&gt;&lt;/A&gt; 
&lt;P align=justify&gt;As you can see we specify the SyncMinTimestamp metadata column as an input parameter. This input parameter would be dynamically filled by the provider. The value is computed by merging the local knowledge with the remote knowledge information returned by the destination provider for GetSyncBatchParamters() method call. The above select command will return all new/updated and deleted rows as well. Next we tell the DbSyncAdapter the names of the tracking columns which represent the TombStone flag and the last change timestamp for the row. DbSyncProvider will populate the IsTombstone property on SyncRowMetadata&amp;nbsp; with the value returned from the IsTombstoneColumn and remove the tracking columns from the DataSet returned to the destination provider.&lt;/P&gt;
&lt;P align=justify&gt;Finally add the DbSyncAdapter to the providers collection. &lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_30.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_30.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=25 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_14.png" width=300 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_14.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Next we need to specify Scope commands on the provider.&lt;/P&gt;
&lt;H1&gt;Step 5. Specify Synchronization Scope commands&lt;/H1&gt;
&lt;P align=justify&gt;Each DbSyncProvider needs certain commands to figure out the current timestamp of the database and to read/update scope information. &lt;/P&gt;
&lt;P align=justify&gt;We need to set the following 3 properties on DbSyncProvider to enable reading timestamp and scope information.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncProvider.SelectNewTimestampProvider&lt;/U&gt;&lt;/STRONG&gt;: This command will enable the provider to determine the current timestamp of the provider (in our sample it will be the current transaction count). Runtime will look for the timestamp in the DbSyncSession.SyncNewTimestamp metadata column so we will specify an output parameter&amp;nbsp; in our query. &lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image83.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image83.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=114 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image83_thumb.png" width=524 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image83_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncProvider.SelectScopeInfoCommand:&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;This command will be used by the provider to select the data knowledge and cleanup knowledge that this provider knows about for this scope. We will retrieve the required information from the query as output parameters. The required output parameters are DbSyncSession.SyncScopeId, SyncScopeKnoeledge, SyncScopeCleanupKnowledge and SyncScopeTimestamp.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image87.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image87.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=334 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image87_thumb.png" width=528 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image87_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncProvider.UpdateScopeInfoCommand:&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;This command will be used by the destination provider to update knowledge and cleanup information each time the provider completes a successful sync from a remote provider. This command is also used when users calls DbSyncProvider.CleanupMetadata() function.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image91.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image91.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=339 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image91_thumb.png" width=523 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image91_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;The runtime will make sure that it passes the right&amp;nbsp; values for all the input parameters. We need to pass the rowcount back to the system in SyncRowCount metadata parameter so that the runtime can detect when update of the scope fails.&lt;/P&gt;
&lt;P align=justify&gt;Finally configure the source DbSyncProvider with the above three commands. &lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_58.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_58.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=52 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_28.png" width=474 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_28.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Thats it. SampleDb1 is now configured to be a DownloadOnly source provider. &lt;/P&gt;
&lt;H1&gt;Step 6. Configure Destination DbSyncProvider&lt;/H1&gt;
&lt;P align=justify&gt;Next we need to create DbSyncProvider representing SampleDb2 database. For this we will create a DbSyncProvider and add the scope specific commands we added in step 4 and 5.&amp;nbsp; Since the database schemas are same we will reuse the same SqlCommands.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_46.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_46.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=109 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_22.png" width=467 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_22.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Then we create a DbSyncAdapter for table Customer.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_48.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_48.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=36 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_23.png" width=442 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_23.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;We will then add the following destination specific properties on the sync adapter.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncAdapter.InsertCommand&lt;/U&gt;&lt;/STRONG&gt;: &lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image42.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image42.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=181 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image42_thumb.png" width=539 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image42_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P align=justify&gt;In this case we are specifying column names we want to insert in Customer table. As you can see the individual column names are specified as input parameters and these parameters will be set with the corresponding column values for each row added on the source provider. We need to explicitly populate the DbSyncSession.SyncRowCount metadata parameter in our insert command as this is how the provider will determine if the insert succeeded or not. Count will always be 1 for a successful insert but will be 0 for either a constraint violation or when a row with the same PK already exists.&lt;/P&gt;
&lt;P align=justify&gt;In case of a PK violation and other conflict scenarios, the provider would try to run the DbSyncAdapter.SelectRowCommand to see what is currently in the table. So we would provide the SelectRowCommand as follows.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image47.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image47.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=63 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image47_thumb.png" width=539 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image47_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P align=justify&gt;I am going to reserve conflict detection to a separate blog post as the workflow and commands involved are slightly different (based on type of PK conflict such as Local delete, remote update or local update, remote update). Suffice to say if Insert failed and SelectRowCommand returns 0 results then it means that its a constraint violation and it will raise DbSyncProvider.ApplyChangeFailed event if one is registered.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncAdapter.InsertMetadataCommand&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;On a successful insert, the provider will then try to insert/update metadata for the currently inserted row. We need to provide the following insert command to insert metadata in CustomerMetadata table.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image59.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image59.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=238 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image59_thumb.png" width=536 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image59_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;We need to return the rowcount back to DbSyncProvider so it can raise a ApplyMetadataFailed event in case its 0.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncAdapter.UpdateMetadataCommand&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;The update command for our sample is as follows.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image63.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image63.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=234 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image63_thumb.png" width=535 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image63_thumb.png"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=justify&gt;On a successful insert of a row(rowcount for InsertCommand &amp;gt; 0), DbSyncProvider assumes the Couple metadata tracking model and hence will first try to execute the UpdateMetadataCommand. In our case the UpdateMetadataCommand will return 0 rowcount and&amp;nbsp; the system will check to see that the model is decoupled and then execute the InsertMetadataCommand. If that fails the ApplyMetadataFailed event will be raised.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncAdapter.UpdateCommand:&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;This command will update existing record in Customer table. Similar to the Insert command we need to return the rowcount back as an output parameter. If update count is 0 then we try to detect whether the row exists by running SelectRowMetadata and resolve the error. If SelectRowMetadata returns 0 then runtime will retry the update as an Insert.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image51.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image51.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=219 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image51_thumb.png" width=537 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image51_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;On successful update, the provider will then execute UpdateMetadataCommand. If that fails (rowcount &amp;lt; 1) then the same fallback procedure mentioned for InsertCommand will be followed.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncAdapter.DeleteCommand:&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;Finally in the delete command we will remove the row from the Customer table.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image55.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image55.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=122 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image55_thumb.png" width=538 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image55_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Once again runtime expects us to return the rowcount as an output parameter. On failure to delete the record it will try execute SelectRowCommand to try to detect conflict as mentioned above. If that fails then it means that the remote peer created and deleted a row before this peer could synchronize. So the system would try to keep tombstone record for that entry by adding a metadata record for that deleted row to guarantee consistent metadata across peers.&lt;/P&gt;
&lt;P align=justify&gt;&lt;STRONG&gt;&lt;U&gt;DbSyncAdapter.DeleteMetadataCommand&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=justify&gt;This command is never used directly. Its only used during a conflict during InsertCommand (and the system tries it as an update) or a conflict in UpdateCommand (in that case the system tries it as an insert). In that case DbSyncProvider will first run the DeleteMetadataCommand and if that is successful will then retry the insert/update.&lt;/P&gt;
&lt;P align=justify&gt;In our sample we will use the following DeleteMetadataCommand.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image67.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image67.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=118 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image67_thumb.png" width=538 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image67_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;With the above mentioned 7 commands the destination specific DbSyncAdapter configuration is complete. We will add this table to the destination DbSyncProvider.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_50.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_50.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=26 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_24.png" width=305 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_24.png"&gt;&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Step 7. Conclusion: Putting it all together&lt;/H1&gt;
&lt;P align=justify&gt;With the source and destination providers set we will start Synchronization by creating a SyncOrchestrator object, set the local and remote providers and set the Direction property to SyncDirectionOrder.Download.&lt;/P&gt;
&lt;P align=justify&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_60.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_60.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=83 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_29.png" width=513 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image_thumb_29.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=justify&gt;Finally we will call Synchronize when the user presses the "Synchronize" button on the winform. &lt;/P&gt;
&lt;H1&gt;Running the sample:&lt;/H1&gt;
&lt;P&gt;Lets start off by running the sample. We will add two rows for John and Jane Doe. Add the rows on the left hand side Customer table and press SaveChanges button. Then refresh the tables to see the metadata created by the triggers.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image103.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image103.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=475 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image103_thumb.png" width=539 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image103_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Next press synchronize and see the left side tables getting the values. Also ensure that the create and update key on the left side metadata column points to 1 and not 0.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image107.png" mce_href="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image107.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=477 alt=image src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image107_thumb.png" width=541 border=0 mce_src="http://blogs.msdn.com/blogfiles/mahjayar/WindowsLiveWriter/GettingstartedwithDbSyncProvider_C915/image107_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;I will leave the update/delete exercise up to the user. To modify the sample to be a two way synchronization, just add the source level DbSyncAdapter commands to SampleDb2 provider and similarly add the destination specific DbSyncAdapter commands to SampleDb1 provider. Then finally change the Direction property on the SyncOrchestrator to DownloadAndUpload.&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Conclusion:&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P&gt;To summarize, we did the following to enable syncing Customer table across peers.&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Created a metadata table for DeCoupled tracking in all peers. &lt;/LI&gt;
&lt;LI&gt;Enabled Snapshot isolation on all peers. &lt;/LI&gt;
&lt;LI&gt;Configured a DbSyncProvider/DbSyncAdapter for SampleDb1 peer and added source peer specific commands. &lt;/LI&gt;
&lt;LI&gt;Configured a DbSyncProvider/DbSyncAdapter for SampleDb2 peer and added destination peer specific commands. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Maheshwar Jayaraman&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8651450" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Framework/default.aspx">Sync Framework</category><category domain="http://blogs.msdn.com/mahjayar/archive/tags/Sync+Services+for+ADO.NET/default.aspx">Sync Services for ADO.NET</category></item></channel></rss>