<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.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>/bill's House O Insomnia&lt;img src="http://www.williamgryan.com/images/originalcuckoo.jpg" alt="Bill Ryan" /&gt; : Microsoft.Synchronization</title><link>http://msmvps.com/blogs/williamryan/archive/tags/Microsoft.Synchronization/default.aspx</link><description>Tags: Microsoft.Synchronization</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>The Microsoft® Windows Mobile Line of Business Solution Accelerator 2008!</title><link>http://msmvps.com/blogs/williamryan/archive/2008/03/17/the-microsoft-174-windows-mobile-line-of-business-solution-accelerator-2008.aspx</link><pubDate>Mon, 17 Mar 2008 13:04:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1545998</guid><dc:creator>William</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/williamryan/rsscomments.aspx?PostID=1545998</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/williamryan/commentapi.aspx?PostID=1545998</wfw:comment><comments>http://msmvps.com/blogs/williamryan/archive/2008/03/17/the-microsoft-174-windows-mobile-line-of-business-solution-accelerator-2008.aspx#comments</comments><description>&lt;p&gt;Rob Tiffany &lt;a href="http://blogs.msdn.com/robtiffany/archive/2008/03/15/a-great-spartan-once-said.aspx"&gt;has got the details...&lt;/a&gt;&amp;nbsp;.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;The main features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;Intelligent resolution awareness&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Synchronization Services&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Windows Communication Foundations &amp;quot;Store and Forward&amp;quot;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;MapPoint&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;LINQ&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Custom Controls&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Managed Stored Procedures and Triggers&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Notifications and Online Help&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Language Switching and Localization&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Some of these (WCF, Synchronization Services) are a lot more thrilling than others but all in all it&amp;#39;s a great step forward.&amp;nbsp; With that said, I think MS really needs to work on a few things. When the iPhones first came out, I was lucky enough to have one sent to me.&amp;nbsp; I liked it but didn&amp;#39;t go gaga over it. After two days, I decided to sell it.&amp;nbsp; I think UI wise, it was far ahead of a typical SmartPhone although the PocketPC edition phones gave it a lot better run for the money.&amp;nbsp; But I know that my opinion is not typical. In fact, most iPhone users who have used or use Windows Mobile are really adamant about the superiority of the UI and usability.&amp;nbsp; I think some of that is b/c they are comparing a 500.00 phone with a much cheaper one in many cases but across the board, the iPhone does probably have the advantage.&amp;nbsp; Having started to toy with the iPhone SDK, I have to admit it&amp;#39;s fairly easy to pick up (nowhere near as easy as the Compact Framework) so once more applications come out for it, it will make it all the more attractive to mainstream users.&amp;nbsp; I have a lot of faith in Microsoft though and nothing would please me more than for Windows Mobile 7.0 to work so well that &lt;a href="http://blah.winsmarts.com/"&gt;my obnoxious iPhone owning friends&lt;/a&gt; will have to pipe down about the greatness of the iPhone.&amp;nbsp; The accelerator however, is definitely a step in the right direction.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1545998" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/williamryan/archive/tags/News/default.aspx">News</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Humor/default.aspx">Humor</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Data+Access/default.aspx">Data Access</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Misc+Technology/default.aspx">Misc Technology</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/WCF/default.aspx">WCF</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/ADO.NET+Synchronization+Services/default.aspx">ADO.NET Synchronization Services</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Microsoft.Synchronization/default.aspx">Microsoft.Synchronization</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Mobility/default.aspx">Mobility</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Sahil+Malik/default.aspx">Sahil Malik</category></item><item><title>Filtering data ADO.NET Synchronization Services</title><link>http://msmvps.com/blogs/williamryan/archive/2007/11/13/filtering-data-ado-net-synchronization-services.aspx</link><pubDate>Wed, 14 Nov 2007 02:20:57 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1308509</guid><dc:creator>William</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/williamryan/rsscomments.aspx?PostID=1308509</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/williamryan/commentapi.aspx?PostID=1308509</wfw:comment><comments>http://msmvps.com/blogs/williamryan/archive/2007/11/13/filtering-data-ado-net-synchronization-services.aspx#comments</comments><description>&lt;p&gt;If you dabble in Orcas or are a data aficionado, then you have probably at least heard of &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=02989F70-49AA-43D7-81B8-A651120F8D65&amp;amp;displaylang=en" target="_blank"&gt;Synchronization Services&lt;/a&gt;.&amp;nbsp; If you haven&amp;#39;t heard of it, let me try to pique your interest.&lt;/p&gt; &lt;p&gt;The business case for &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=02989F70-49AA-43D7-81B8-A651120F8D65&amp;amp;displaylang=en" target="_blank"&gt;Sync Services&lt;/a&gt;&amp;nbsp;is simple. You have data in one place and you want to sync it with Data in another place.&amp;nbsp; This is an old school problem that has been dealt with many times before by many different people. That should clue you in to the realization that such problems should probably be approached using design patterns and &lt;a href="http://msdn2.microsoft.com/en-us/library/ms998449.aspx" target="_blank"&gt;Data Oriented Design Patterns in particular&lt;/a&gt;.&amp;nbsp; My memory is a little foggy but I don&amp;#39;t specifically remember reading any &amp;#39;data movement patterns&amp;#39; in the seminal design pattern book, &amp;nbsp;&lt;a href="http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612" target="_blank"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;&amp;nbsp;by the &lt;a href="http://en.wikipedia.org/wiki/Design_Patterns" target="_blank"&gt;Gang of Four&lt;/a&gt;.&amp;nbsp; (As a slight digression, I&amp;#39;ve found quite a few superb design pattern books and a few stinkers.&amp;nbsp; The GOF book is by far the best one I&amp;#39;ve come across in terms of being understandable and easy to follow and can say with comfort that it won&amp;#39;t disappoint).&lt;/p&gt; &lt;p&gt;So you can roll your own code, you can use an existing mechanism like Replication, or you can go new school and try SS. I don&amp;#39;t claim to be an expert at SS but so far, I&amp;#39;ve found it shocking easily to use and learn. Of all the zillions of new MS products rolling out of Microsoft, SS is one of the easiest I&amp;#39;ve come across, at least in terms of getting up and running.&lt;/p&gt; &lt;p&gt;Now, chances are that if you have the need to sync data back and forth (for instance, moving data from a database server to your salesforce&amp;#39;s Tablet PC&amp;#39;s), you will have a lot more data on your server than you&amp;#39;d need or be able to use on the remote machine. Even if you wanted all of that data, in many cases you won&amp;#39;t be able to get it all b/c moving it would take forever and the target machine is resource constrained. To that end, the out of the box demo code that ships with SS will need some modification.&lt;/p&gt; &lt;p&gt;The first point I&amp;#39;d make is that Yes, it is possible to sync only portions of the data.&amp;nbsp; This came up recently in one of the newsgroups I frequent and it&amp;#39;s an excellent question.&amp;nbsp; Just to get a conceptual feel for this, think of the same scenario I mentioned earlier. You have a db server and a mobile salesforce (or nursing force, or delivery force, or you&amp;#39;re a large law firm, consulting group, accounting practice...you get the idea) and you only need to sync each target machine with a subset of data. In an ideal world remote users could see everything that&amp;nbsp;users at the&amp;nbsp;home base could, but moving the data could take forever in many large companies. Moreover, you probably wouldn&amp;#39;t need most of it.&amp;nbsp; If you&amp;#39;re a nurse that makes house calls,&amp;nbsp;you probably wouldn&amp;#39;t need information for people that have passed on, or that have moved or even that you&amp;#39;re not visiting. If your device was a PDA, you need to&amp;nbsp;economize on every resource possible. But even if you had a laptop or tablet you still&amp;nbsp;have&amp;nbsp;some resource limits.&amp;nbsp;Hence,&amp;nbsp;envision a case where&amp;nbsp;you might just want to sync only the data related to each person&amp;#39;s active clients (and probably augment the query&amp;#39;s restriction with a date filter of some sort and perhaps an active account indicator) that have engaged in at least one transaction in the last year.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You could give each person some sort of UI tool which they could initiate that queries the db and writes the data to a file, which they in turn copy over to their machine.&lt;/li&gt; &lt;li&gt;You could do the same thing, but run it as a job so it&amp;#39;s done automatically&lt;/li&gt; &lt;li&gt;You could expose the query results as a web service and let them retrieve data as they needed it&lt;/li&gt; &lt;li&gt;You could export the data to Excel or Access (the latter of which I&amp;#39;ve seen done more times than I care to remember)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Each of these approaches is easy enough to implement but has major suckiness associated with it.&amp;nbsp; The first approach is one of the simpler ones and fairly fool-proof.&amp;nbsp; Writing out the file is something you could automate via a schedule but not copying it to the device, unless of course you were positive the device would always be available when the job ran.&amp;nbsp; With the web service, you&amp;#39;re depending on internet connectivity which, even in this day where everyone has mobile broadband, there are still a lot of coverage holes. If you had any sort of substantial dataset, pulling it down over a mobile broadband connection would be a doubleplusbad. Copying it to Access or Excel would have the same issues and shortcomings that the first approach, after all it really is the same approach but simply uses a different file format.&lt;/p&gt; &lt;p&gt;Referring to the &lt;font face="Courier New"&gt;SyncServices_CSharp_DownloadOnly&lt;/font&gt; sample included in the Sync Services install, refer to the &lt;font face="Courier New"&gt;SampleServerSyncProvider&lt;/font&gt; method of the &lt;font face="Courier New"&gt;&lt;em&gt;SampleServerSyncProvider.cs&lt;/em&gt;&lt;/font&gt; or &lt;font face="Courier New"&gt;&lt;em&gt;SampleServerSyncProvider.vb&lt;/em&gt;&lt;/font&gt; file, you see the following code (the Author was kind enough to include copious comments which explain each portion - I&amp;#39;ve removed them for readability but would encourage you to refer to them if you&amp;#39;re unfamiliar with Sync Service):&lt;/p&gt; &lt;p&gt;public class SampleServerSyncProvider : DbServerSyncProvider&lt;br /&gt;&amp;nbsp;&amp;nbsp; { &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public SampleServerSyncProvider()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Connection = new SqlConnection(Properties.Settings.Default.ServerConnString); &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;string awNewAnchorVariable = &amp;quot;@&amp;quot; + SyncSession.SyncNewReceivedAnchor;&lt;br /&gt;SqlCommand selectNewAnchorCommand = new SqlCommand();&lt;br /&gt;selectNewAnchorCommand.CommandText = &amp;quot;SELECT &amp;quot; + awNewAnchorVariable + &amp;quot; = @@DBTS&amp;quot;;&lt;br /&gt;selectNewAnchorCommand.Parameters.Add(awNewAnchorVariable, SqlDbType.Timestamp);&lt;br /&gt;selectNewAnchorCommand.Parameters[awNewAnchorVariable].Size = 8;&lt;br /&gt;selectNewAnchorCommand.Parameters[awNewAnchorVariable].Direction = ParameterDirection.Output;&lt;br /&gt;selectNewAnchorCommand.Connection = (SqlConnection)this.Connection;&lt;br /&gt;this.SelectNewAnchorCommand = selectNewAnchorCommand;&lt;/font&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;SqlSyncAdapterBuilder builder = new SqlSyncAdapterBuilder((SqlConnection)this.Connection); &lt;/p&gt; &lt;p&gt;&lt;br /&gt;&amp;nbsp;&lt;font color="#008080"&gt;builder.TableName = &amp;quot;Sales.Customer&amp;quot;;&lt;br /&gt;&amp;nbsp;builder.TombstoneTableName = builder.TableName + &amp;quot;_Tombstone&amp;quot;;&lt;br /&gt;&amp;nbsp;builder.TombstoneFilterClause = filterCommand;&lt;/font&gt;&amp;nbsp; &lt;p&gt;&lt;br /&gt;&amp;nbsp;builder.DataColumns.Add(&amp;quot;CustomerId&amp;quot;);&lt;br /&gt;&amp;nbsp;builder.DataColumns.Add(&amp;quot;CustomerName&amp;quot;);&lt;br /&gt;&amp;nbsp;builder.DataColumns.Add(&amp;quot;SalesPerson&amp;quot;);  &lt;p&gt;&lt;br /&gt;&amp;nbsp;builder.CreationTrackingColumn = &amp;quot;InsertTimestamp&amp;quot;;&lt;br /&gt;&amp;nbsp;builder.UpdateTrackingColumn = &amp;quot;UpdateTimestamp&amp;quot;;&lt;br /&gt;&amp;nbsp;builder.DeletionTrackingColumn = &amp;quot;DeleteTimestamp&amp;quot;;  &lt;p&gt;&lt;br /&gt;&amp;nbsp;SyncAdapter customerSyncAdapter = builder.ToSyncAdapter();&lt;br /&gt;&amp;nbsp;customerSyncAdapter.TableName = &amp;quot;Customer&amp;quot;;&lt;br /&gt;&amp;nbsp;this.SyncAdapters.Add(customerSyncAdapter);&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;}&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;[Note:&amp;nbsp; Even with the comments, some of this code may be hard to follow when you first read it.&amp;nbsp; One thing I did which was very enlightening and always a useful thing to do in such situations is fire up good ole&amp;#39; Sql Profiler, then run the application and see exactly what happens, what objects are being used and what commands are being sent to the db]. &lt;p&gt;I show some of the relevant results from the trace below (I&amp;#39;ve color coded the results to the portion of the code that which caused it to happen): &lt;blockquote&gt; &lt;p&gt;&lt;font color="#0000ff"&gt;declare @p3 binary(8)&lt;br /&gt;set @p3=0x0000000000000FA0&lt;br /&gt;exec sp_executesql N&amp;#39;SELECT @sync_new_received_anchor = @@DBTS&amp;#39;,N&amp;#39;@sync_new_received_anchor timestamp &lt;br /&gt;output&amp;#39;,@sync_new_received_anchor=@p3 output&lt;br /&gt;select @p3&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#408080"&gt;exec sp_executesql N&amp;#39;SELECT [CustomerId], [CustomerName], [SalesPerson] FROM Sales.Customer WHERE&amp;nbsp;&lt;br /&gt; (InsertTimestamp &amp;gt; @sync_last_received_anchor AND InsertTimestamp &amp;lt;= &lt;br /&gt;@sync_new_received_anchor)&amp;#39;,N&amp;#39;@sync_last_received_anchor binary(8000),@sync_new_received_anchor &lt;br /&gt;binary(8)&amp;#39;,@sync_last_received_anchor=0x00,@sync_new_received_anchor=0x0000000000000FA0&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#008080"&gt;exec sp_executesql N&amp;#39;SELECT [CustomerId], [CustomerName], [SalesPerson] FROM Sales.Customer WHERE &lt;br /&gt;(CustomerName=&amp;#39;&amp;#39;Sharp Bikes&amp;#39;&amp;#39;) AND (UpdateTimestamp &amp;gt; @sync_last_received_anchor AND UpdateTimestamp &amp;lt;= &lt;br /&gt;@sync_new_received_anchor AND InsertTimestamp &amp;lt;= @sync_last_received_anchor)&amp;#39;,N&amp;#39;@sync_last_received_anchor &lt;br /&gt;timestamp,@sync_new_received_anchor &lt;br /&gt;timestamp&amp;#39;,@sync_last_received_anchor=0x0000000000000000,@sync_new_received_anchor=0x0000000000000FA0&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#008080"&gt;exec sp_executesql N&amp;#39;SELECT [CustomerId], [CustomerName], [SalesPerson], [CustomerType], [DeleteId], &lt;br /&gt;[DeleteTimestamp] FROM Sales.Customer_Tombstone WHERE (CustomerName=&amp;#39;&amp;#39;Sharp Bikes&amp;#39;&amp;#39;) AND (@sync_initialized = 1 &lt;br /&gt;AND DeleteTimestamp &amp;gt; @sync_last_received_anchor AND DeleteTimestamp &amp;lt;= &lt;br /&gt;@sync_new_received_anchor)&amp;#39;,N&amp;#39;@sync_initialized bit,@sync_last_received_anchor &lt;br /&gt;timestamp,@sync_new_received_anchor &lt;br /&gt;timestamp&amp;#39;,@sync_initialized=0,@sync_last_received_anchor=NULL,@sync_new_received_anchor=0x0000000000000FA0&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp; &lt;p&gt;As it stands, the code above is pulling everything from the &lt;font face="Courier New"&gt;Sales.Customer&lt;/font&gt; table.&amp;nbsp; But as I mentioned, chances are that you wouldn&amp;#39;t want the whole resultset. Rather, you&amp;#39;d probably want a filtered subset.&amp;nbsp; For the sake of visual simplicity, I&amp;#39;m going to violate one of my biggest coding Pet Peeves and concatenate a sql statement to include a parameter instead of doing it the right way, but I&amp;#39;ll show the correct way shortly. &lt;p&gt;The &lt;font face="Courier New"&gt;SqlSyncAdapterBuilder&lt;/font&gt; has several properties and for filtering purposes, you can simply set the &lt;font face="Courier New"&gt;FilterClause&lt;/font&gt; property.&amp;nbsp; Starting with the code beginning at the adapter instantiation, I modified the code to just return records that have a &lt;font face="Courier New"&gt;CustomerName&lt;/font&gt; value equal to the literal &amp;#39;&lt;font face="Courier New"&gt;Sharp Bikes&amp;#39; (The relevant portions are included in &lt;strong&gt;Bold &lt;/strong&gt;face)&lt;/font&gt;: &lt;blockquote&gt; &lt;p&gt;SqlSyncAdapterBuilder builder = new SqlSyncAdapterBuilder((SqlConnection)this.Connection);  &lt;p&gt;&lt;br /&gt;&lt;strong&gt;String FilterCommand = &amp;quot;CustomerName=&amp;#39;Sharp Bikes&amp;#39;&amp;quot;;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;builder.TableName = &amp;quot;Sales.Customer&amp;quot;;&lt;br /&gt;builder.TombstoneTableName = builder.TableName + &amp;quot;_Tombstone&amp;quot;;&lt;br /&gt;&lt;strong&gt;builder.FilterClause = FilterCommand ;&lt;br /&gt;builder.TombstoneFilterClause = FilterCommand;&lt;/strong&gt; &lt;/p&gt; &lt;p&gt;builder.SyncDirection = SyncDirection.DownloadOnly;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;So, it&amp;#39;s pretty much this easy, you simply need to set the FilterClause property of the &lt;font face="Courier New"&gt;SqlSyncAdapterBuilder&lt;/font&gt; and absent some really compelling reason to do so, set the &lt;font face="Courier New"&gt;TombStoneFilterClause&lt;/font&gt; to the same value.&amp;nbsp; Because you use the same statement, it&amp;#39;s best to use a String literal so that the two &lt;font face="Courier New"&gt;FilterClause&lt;/font&gt; values don&amp;#39;t get out of sync. Just as you set the &lt;font face="Courier New"&gt;FilterClause&lt;/font&gt; and &lt;font face="Courier New"&gt;TombstoneFilterClause&lt;/font&gt; properties to facilitate filtering, if you use a parameter, you need to add a &lt;font face="Courier New"&gt;SqlParameter&lt;/font&gt; (or &lt;font face="Courier New"&gt;SqlParameter&lt;/font&gt;(s)) to the &lt;font face="Courier New"&gt;FilterParameters&lt;/font&gt; and &lt;font face="Courier New"&gt;TombstoneFilterParameters&lt;/font&gt; collections.&amp;nbsp; So, the below code shows the previous snippet modified to use a &lt;font face="Courier New"&gt;SqlParameter&lt;/font&gt; instead of concatenating the Sql text, again, the relevant portions are included in &lt;strong&gt;Bold &lt;/strong&gt;face: &lt;blockquote&gt; &lt;p&gt;SqlSyncAdapterBuilder builder = new SqlSyncAdapterBuilder((SqlConnection)this.Connection);&lt;br /&gt;SqlParameter CustomerNameParameter = new SqlParameter(&amp;quot;@CustomerName&amp;quot;, SqlDbType.NVarChar);  &lt;p&gt;&lt;br /&gt;&lt;strong&gt;String FilterCommand = &amp;quot;CustomerName=@CustomerName&amp;quot;;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;builder.TableName = &amp;quot;Sales.Customer&amp;quot;;&lt;br /&gt;builder.TombstoneTableName = builder.TableName + &amp;quot;_Tombstone&amp;quot;;&lt;br /&gt;builder.FilterClause = FilterCommand ;&lt;br /&gt;builder.TombstoneFilterClause = FilterCommand;&lt;br /&gt;&lt;strong&gt;builder.FilterParameters.Add(CustomerNameParameter);&lt;br /&gt;builder.TombstoneFilterParameters.Add(CustomerNameParameter);&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now the results from Profiler show something notably different: &lt;blockquote&gt; &lt;p&gt;exec sp_executesql N&amp;#39;SELECT [CustomerId], [CustomerName], [SalesPerson] FROM Sales.Customer WHERE &lt;br /&gt;(&lt;font size="3"&gt;&lt;strong&gt;&lt;em&gt;CustomerName=@CustomerName&lt;/em&gt;&lt;/strong&gt;&lt;/font&gt;) AND (InsertTimestamp &amp;gt; @sync_last_received_anchor AND InsertTimestamp &amp;lt;= &lt;br /&gt;@sync_new_received_anchor)&amp;#39;,N&amp;#39;@CustomerName nvarchar(11),@sync_last_received_anchor &lt;br /&gt;binary(8000),@sync_new_received_anchor binary(8)&amp;#39;,@&lt;strong&gt;&lt;font size="3"&gt;&lt;em&gt;CustomerName=N&amp;#39;Sharp &lt;br /&gt;Bikes&amp;#39;&lt;/em&gt;&lt;/font&gt;&lt;/strong&gt;,@sync_last_received_anchor=0x00,@sync_new_received_anchor=0x0000000000000FA0&lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;exec sp_executesql N&amp;#39;SELECT [CustomerId], [CustomerName], [SalesPerson] FROM Sales.Customer WHERE &lt;br /&gt;(&lt;font size="3"&gt;&lt;strong&gt;&lt;em&gt;CustomerName=@CustomerName&lt;/em&gt;&lt;/strong&gt;&lt;/font&gt;) AND (UpdateTimestamp &amp;gt; @sync_last_received_anchor AND UpdateTimestamp &amp;lt;= &lt;br /&gt;@sync_new_received_anchor AND InsertTimestamp &amp;lt;= @sync_last_received_anchor)&amp;#39;,N&amp;#39;@CustomerName &lt;br /&gt;nvarchar(11),@sync_last_received_anchor timestamp,@sync_new_received_anchor timestamp&amp;#39;,@&lt;font size="3"&gt;&lt;strong&gt;&lt;em&gt;CustomerName=N&amp;#39;Sharp &lt;br /&gt;Bikes&amp;#39;&lt;/em&gt;&lt;/strong&gt;&lt;/font&gt;,@sync_last_received_anchor=0x0000000000000000,@sync_new_received_anchor=0x0000000000000FA0&lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;exec sp_executesql N&amp;#39;SELECT [CustomerId], [CustomerName], [SalesPerson], [CustomerType], [DeleteId], &lt;br /&gt;[DeleteTimestamp] FROM Sales.Customer_Tombstone WHERE (&lt;font size="3"&gt;&lt;strong&gt;&lt;em&gt;CustomerName=@CustomerName&lt;/em&gt;&lt;/strong&gt;&lt;/font&gt;) AND (@sync_initialized = 1 &lt;br /&gt;AND DeleteTimestamp &amp;gt; @sync_last_received_anchor AND DeleteTimestamp &amp;lt;= &lt;br /&gt;@sync_new_received_anchor)&amp;#39;,N&amp;#39;@CustomerName nvarchar(11),@sync_initialized bit,@sync_last_received_anchor &lt;br /&gt;timestamp,@sync_new_received_anchor timestamp&amp;#39;&lt;font size="3"&gt;&lt;strong&gt;&lt;em&gt;,@CustomerName=N&amp;#39;Sharp &lt;br /&gt;Bikes&amp;#39;&lt;/em&gt;&lt;/strong&gt;&lt;/font&gt;,@sync_initialized=0,@sync_last_received_anchor=NULL,@sync_new_received_anchor=0x0000000000000FA0&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;You can see here clearly that not only is the &lt;font face="Courier New"&gt;@CustomerName&lt;/font&gt; parameter being used, it&amp;#39;s being set to the literal &lt;font face="Courier New"&gt;Sharp Bikes&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;There&amp;#39;s one catch though when using real parameters. If you modify the code as I did above and try to run it, you&amp;#39;ll encounter the following exception:&lt;/p&gt; &lt;p&gt;&amp;nbsp; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;Microsoft.Synchronization.Data.SessionVariableException was unhandled&lt;br /&gt;&amp;nbsp; Message=&amp;quot;Unable to set session parameters in DbServerSyncProvider. Cannot obtain the value for command parameter &amp;#39;@CustomerName&amp;#39;.&amp;quot;&lt;br /&gt;&amp;nbsp; Source=&amp;quot;Microsoft.Synchronization.Data.Server&amp;quot;&lt;br /&gt;&amp;nbsp; SyncSource=&amp;quot;ServerSyncProvider&amp;quot;&lt;br /&gt;&amp;nbsp; StackTrace:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at Microsoft.Synchronization.Data.Server.DbServerSyncProvider.SetSessionParameters(IDbCommand cmd, SyncGroupMetadata groupMetadata, SyncTableMetadata tableMetadata, SyncSession syncSession, DataColumnCollection columns, SyncStage stage)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at Microsoft.Synchronization.Data.Server.DbServerSyncProvider.EnumerateChanges(SyncGroupMetadata groupMetadata, SyncSession syncSession, IDbTransaction transaction, EnumerateChangeType changeType)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at Microsoft.Synchronization.Data.Server.DbServerSyncProvider.GetChanges(SyncGroupMetadata groupMetadata, SyncSession syncSession)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at Microsoft.Synchronization.SyncAgent.DownloadChanges(SyncGroupMetadata groupMetadata)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at Microsoft.Synchronization.SyncAgent.Synchronize()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; at Microsoft.Samples.Synchronization.MainForm.btnSynchronize_Click(Object sender, EventArgs e) in C:\SyncServicesCode\SyncServices_CSharp_DownloadOnly\Client\Forms\MainForm.cs:...&lt;/font&gt;&lt;/em&gt;&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Nothing too shocking though right, after all, although we specified a parameter be used in the &lt;font face="Courier New"&gt;CommandText&lt;/font&gt; property, we never set the value so it&amp;#39;s not surprising that an exception was thrown unless the parameter had a default value, which in this case it clearly did not.  &lt;p&gt;But if you change the code to explicitly set the value for the parameter, for instance like this... &lt;blockquote&gt; &lt;p&gt;SqlParameter CustomerNameParameter = new SqlParameter(&amp;quot;@CustomerName&amp;quot;, SqlDbType.NVarChar);&lt;br /&gt;&lt;strong&gt;CustomerNameParameter.Value = &amp;quot;Sharp Bikes&amp;quot;;&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;you&amp;#39;ll still get the same exception.&amp;nbsp; This really threw me for a loop b/c I used the debugger and &lt;em&gt;proved&lt;/em&gt; to myself that the value wasn&amp;#39;t null or left out. If you step through with the debugger, you can verify for yourself that the above code is in fact setting the value of &lt;font face="Courier New"&gt;@CustomerName = &amp;quot;Sharp Bikes&amp;quot;&lt;/font&gt; &lt;p&gt;One point that&amp;#39;s extremely important... Normally, as long as you modify your &lt;font face="Courier New"&gt;CommandText&lt;/font&gt; to refer to the&amp;nbsp;&lt;font face="Courier New"&gt;SqlParameter&lt;/font&gt;&amp;nbsp; and&amp;nbsp;add a &lt;font face="Courier New"&gt;SqlParameter&lt;/font&gt; object to a &lt;font face="Courier New"&gt;SqlCommand&lt;/font&gt; object&amp;#39;s &lt;font face="Courier New"&gt;Parameters&lt;/font&gt; collection, you don&amp;#39;t need to do anything else. But as I just babbled on about, that won&amp;#39;t cut it here... something is still missing. &lt;p&gt;As it turns out, (and makes perfect sense once I cleared my tunnel vision), the &lt;font face="Courier New"&gt;SyncAgent &lt;/font&gt;(&lt;em&gt;Microsoft.Synchronization.SyncAgent&lt;/em&gt;) class is what actually does much of the heavy lifting and just because you have a Parameter referenced in code in your &lt;font face="Courier New"&gt;SqlSyncAdapterBuilder&lt;/font&gt;, the &lt;font face="Courier New"&gt;SyncAgent&lt;/font&gt; doesn&amp;#39;t know anything about it. Since it doesn&amp;#39;t know anything about it, it doesn&amp;#39;t know to pass in a value or what value to pass to it, so when it tries to finish processing the value for the parameter isn&amp;#39;t set. It didn&amp;#39;t matter that we set it explicitly because we set it in the wrong place. &lt;p&gt;Fortunately, it&amp;#39;s very easy to address.&amp;nbsp; The code below is the&lt;font face="Courier New"&gt; SyncAgent&amp;#39;s&lt;/font&gt; code, the last line in Bold is what you need to add if you&amp;#39;re using a parameterized filter: &lt;p&gt;public class SampleSyncAgent : Microsoft.Synchronization.SyncAgent&lt;br /&gt;&amp;nbsp;{ &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public SampleSyncAgent()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlCeClientSyncProvider clientSyncProvider = new SqlCeClientSyncProvider(Properties.Settings.Default.ClientConnString, true);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.LocalProvider = clientSyncProvider;&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;&amp;nbsp; clientSyncProvider.ChangesApplied += new EventHandler&amp;lt;ChangesAppliedEventArgs&amp;gt;(clientSyncProvider_ChangesApplied);  &lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.RemoteProvider = new SampleServerSyncProvider();  &lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SyncTable customerSyncTable = new SyncTable(&amp;quot;Customer&amp;quot;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; customerSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; customerSyncTable.SyncDirection = SyncDirection.DownloadOnly;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Configuration.SyncTables.Add(customerSyncTable);&lt;br /&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Configuration.SyncParameters.Add(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new SyncParameter(&amp;quot;@CustomerName&amp;quot;, &amp;quot;Sharp Bikes&amp;quot;));&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;p&gt;} &lt;p&gt;(Part of this class was left out for brevity - all that is missing is the private variables and their corresponding public properties). &lt;p&gt;The corresponding code is available &lt;a href="http://www.williamgryan.com/downloads/code/syncservices" target="_blank"&gt;Here&lt;/a&gt;.&amp;nbsp; Please note that this code is taken from the Synchronization Services samples that are included when you install Synchronization Services.&amp;nbsp; I merely modified that code to support parameterized filters.&amp;nbsp; I will be adding a UI Element on the MainForm object so that you can set the value dynamically instead of hard coding it as I did.&amp;nbsp; Again, although this post is a little long, we really are talking about basically adding less than 10 lines of code to add filtering. You need to set the FilterClause, the TombstoneFilterClause, FilterParameters, TombstoneFilterParameters and then add a SyncParameter to the SyncAgent.&amp;nbsp; As you can infer, you if you need more expressions, you can just add them accordingly to meet whatever your requirements happen to be. &lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1308509" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Compact+Framework/default.aspx">Compact Framework</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Coding+Techniques/default.aspx">Coding Techniques</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/ADO.NET+Synchronization+Services/default.aspx">ADO.NET Synchronization Services</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/.NET+3.0+Framework/default.aspx">.NET 3.0 Framework</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/DBServerSyncProvider/default.aspx">DBServerSyncProvider</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Synchronization+Services/default.aspx">Synchronization Services</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/SyncAgent/default.aspx">SyncAgent</category><category domain="http://msmvps.com/blogs/williamryan/archive/tags/Microsoft.Synchronization/default.aspx">Microsoft.Synchronization</category></item></channel></rss>