<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rob Tiffany &#187; Database</title>
	<atom:link href="http://robtiffany.com/tag/database/feed/" rel="self" type="application/rss+xml" />
	<link>http://robtiffany.com</link>
	<description>Author, Mobility Strategist at Microsoft, Speaker, Advisor, Technology Executive, Former Navy Submariner</description>
	<lastBuildDate>Wed, 16 May 2012 01:19:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>What Developers in Small Companies are Using</title>
		<link>http://robtiffany.com/what-developers-in-small-companies-are-using/</link>
		<comments>http://robtiffany.com/what-developers-in-small-companies-are-using/#comments</comments>
		<pubDate>Fri, 09 Dec 2011 17:01:44 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[Bug Tracking]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Developer]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[Project Management]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[Text Editor]]></category>
		<category><![CDATA[Version Control]]></category>
		<category><![CDATA[Web Hosting]]></category>
		<category><![CDATA[Website Analytics]]></category>

		<guid isPermaLink="false">http://robtiffany.com/software/what-developers-in-small-companies-are-using</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><img src="http://api.viglink.com/api/click?format=go&amp;key=021de175e1e571c67cfaeea3c68d72e8&amp;loc=http%3A%2F%2Fwww.readwriteweb.com%2Fhack%2F2011%2F12%2Finfographic-what-tools-develop.php&amp;v=1&amp;libid=1323449648031&amp;out=http%3A%2F%2Frww.readwriteweb.netdna-cdn.com%2Fhack%2FBV%2520Developer%2520Infographic.jpg&amp;ref=http%3A%2F%2Fwww.readwriteweb.com%2F&amp;title=Infographic%3A%20What%20Tools%20Developers%20Actually%20Use&amp;txt=&amp;jsonp=vglnk_jsonp_13234496851722" width="1199" height="3687" /></p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/what-developers-in-small-companies-are-using/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A Quick Note on Speedy, Scalable, Available Architectures</title>
		<link>http://robtiffany.com/a-quick-note-on-speedy-scalable-available-architectures/</link>
		<comments>http://robtiffany.com/a-quick-note-on-speedy-scalable-available-architectures/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 15:23:09 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Availability]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Cluster]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Horizontal Scale]]></category>
		<category><![CDATA[Load Balance]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Private Cloud]]></category>
		<category><![CDATA[Queue]]></category>
		<category><![CDATA[Relational]]></category>
		<category><![CDATA[Replication]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Shard]]></category>
		<category><![CDATA[Speed]]></category>
		<category><![CDATA[Web Service]]></category>

		<guid isPermaLink="false">http://robtiffany.com/architecture/a-quick-note-on-speedy-scalable-available-architectures</guid>
		<description><![CDATA[Just a few thoughts on concepts needed to give mobile users of your SOA infrastructure the best, fastest User eXperience possible: If you care about speed &#38; scalability, your web service will always check the distributed cache before querying the &#8230; <a href="http://robtiffany.com/a-quick-note-on-speedy-scalable-available-architectures/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Just a few thoughts on concepts needed to give mobile users of your SOA infrastructure the best, fastest User eXperience possible:</p>
<ul>
<li>If you care about speed &amp; scalability, your web service will always check the distributed cache before querying the database.</li>
<li>If you have to get your answer from your database, make sure to add the answer to your distributed cache concurrently with returning it to the user.</li>
<li>Don’t ever call your primary database directly.  Call one of your horizontally-scaled relational or NoSQL replicas.</li>
<li>Use download-only replication to create as many read-only replicas as you need.  Your replicas can contain complete copies of the primary database or just shards of data as appropriate.</li>
<li>When sending data up from the clients to your servers, never let your web services insert, update, or delete directly against the primary database or the replicas.</li>
<li>Have your web services drop that uploaded data in a queue and update the distributed cache while letting worker processes perform those DML operations against the primary database.</li>
<li>Use peer-to-peer replication to maintain more than one read/write primary database at the top of your hierarchy.</li>
<li>Remember to create and maintain more than one hierarchy in different geographies using the same peer-to-peer replication to provide even more availability, scalability, and performance to your mobile users all around the world.</li>
<li>Your mobile users will be connecting to your service via slow, intermittent, unpredictable wireless data networks so always use small, efficient wire protocols like REST and data serialization like JSON.</li>
</ul>
<p>-Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/a-quick-note-on-speedy-scalable-available-architectures/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sync Framework v4 is now Open Source, and ready to Connect any Device to SQL Server and SQL Azure</title>
		<link>http://robtiffany.com/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/</link>
		<comments>http://robtiffany.com/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/#comments</comments>
		<pubDate>Sun, 11 Sep 2011 20:54:27 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Sync Framework]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Consumerization]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[MEAP]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Synchronize]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[Windows Mobile]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=1014</guid>
		<description><![CDATA[The profound effects of the Consumerization of IT (CoIT) is blurring the lines between consumers and the enterprise.  The fact that virtually every type of mobile device is now a candidate to make employees productive means that cross-platform, enabling technologies are &#8230; <a href="http://robtiffany.com/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The profound effects of the Consumerization of IT (CoIT) is blurring the lines between consumers and the enterprise.  The fact that virtually every type of mobile device is now a candidate to make employees productive means that cross-platform, enabling technologies are a must.  Luckily, Microsoft has brought the power to synchronize data with either SQL Server on-premise or SQL Azure in the cloud to the world of mobility.  If you&#8217;ve ever synched the music on your iPhone with iTunes, the calendar on your Android device with Gmail, or the Outlook email on your Windows Phone with Exchange, then you understand the importance of sync.  In my experience architecting and building enterprise mobile apps for the world&#8217;s largest organizations over the last decade, data sync has always been a critical ingredient.</p>
<p><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/sql-azure_rgb_2" rel="attachment wp-att-1027"><img class="alignright size-medium wp-image-1027" title="SQL Azure" src="http://robtiffany.com/wp-content/uploads/2011/09/SQL-Azure_rgb_2-300x92.png" alt="" width="300" height="92" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/microsoft-sql-server-2008" rel="attachment wp-att-1026"><img class="aligncenter size-medium wp-image-1026" title="SQL Server" src="http://robtiffany.com/wp-content/uploads/2011/09/microsoft-sql-server-2008-300x246.jpg" alt="" width="300" height="246" /></a></p>
<p>The new <strong><a title="Sync Framework Toolkit" href="http://code.msdn.microsoft.com/Sync-Framework-Toolkit-4dc10f0e" target="_blank">Sync Framework Toolkit</a></strong> found on MSDN builds on the existing Sync Framework 2.1&#8242;s ability to create disconnected applications, making it easier to expose data for synchronization to apps running on any client platform.  Where Sync Framework 2.1 required clients to be based on Windows, this free toolkit allows other Microsoft platforms to be used for offline clients such as Silverlight, Windows Phone 7, Windows Mobile, Windows Embedded Handheld, and new Windows Slates.   Additionally, non-Microsoft platforms such as iPhones, iPads, Android phones and tablets, Blackberries and browsers supporting HTML5 are all first-class sync citizens.  The secret is that we no longer require the installation of the Sync Framework runtime on client devices.  When coupled with use of an open protocol like <a title="OData" href="http://www.odata.org/" target="_blank">OData </a>for data transport, no platform or programming language is prevented from synchronizing data with our on-premise and cloud databases.  When the data arrives on your device, you can serialize it as JSON, or insert it into SQL Server Compact or SQLite depending on your platform preferences.</p>
<p><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/sync" rel="attachment wp-att-1032"><img class="aligncenter size-full wp-image-1032" title="sync" src="http://robtiffany.com/wp-content/uploads/2011/09/sync.png" alt="" width="256" height="256" /></a>The Sync Framework Toolkit provides all the features enabled by the<a href="http://blogs.msdn.com/b/sync/archive/2010/11/16/sync-framework-4-0-october-2010-ctp-refreshed-on-11-16.aspx">Sync Framework 4.0 October 2010 CTP</a>.  We are releasing the toolkit as source code samples on MSDN with the source code utilizing Sync Framework 2.1.  Source code provides the flexibility to customize or extend the capabilities we have provided to suit your specific requirements. The client-side source code in the package is released under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache 2.0 license</a> and the server-side source code under the <a href="http://mef.codeplex.com/license">MS-LPL license</a>.  The Sync Framework 2.1 is fully supported by Microsoft and the mobile-enabling source code is yours to use, build upon, and support for the apps you create.</p>
<p><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/windowsslate" rel="attachment wp-att-1051"><img class="alignleft size-full wp-image-1051" title="WindowsSlate" src="http://robtiffany.com/wp-content/uploads/2011/09/WindowsSlate.png" alt="" width="182" height="115" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/windowsphone" rel="attachment wp-att-1050"><img class="alignleft size-full wp-image-1050" title="WindowsPhone" src="http://robtiffany.com/wp-content/uploads/2011/09/WindowsPhone.png" alt="" width="152" height="153" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/mc55a0_lg_us-en-2" rel="attachment wp-att-1048"><img class="alignleft size-thumbnail wp-image-1048" title="MC55A0_LG_US-EN" src="http://robtiffany.com/wp-content/uploads/2011/09/MC55A0_LG_US-EN1-150x150.jpg" alt="" width="150" height="150" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/html5_logo_512" rel="attachment wp-att-1045"><img class="alignleft size-thumbnail wp-image-1045" title="HTML5_Logo_512" src="http://robtiffany.com/wp-content/uploads/2011/09/HTML5_Logo_512-150x150.png" alt="" width="150" height="150" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/mac" rel="attachment wp-att-1047"><img class="alignleft size-full wp-image-1047" title="Mac" src="http://robtiffany.com/wp-content/uploads/2011/09/Mac.png" alt="" width="184" height="106" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/blackberry" rel="attachment wp-att-1044"><img class="alignleft size-full wp-image-1044" title="Blackberry" src="http://robtiffany.com/wp-content/uploads/2011/09/Blackberry.png" alt="" width="173" height="173" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/ipad" rel="attachment wp-att-1046"><img class="alignleft size-full wp-image-1046" title="iPad" src="http://robtiffany.com/wp-content/uploads/2011/09/iPad.png" alt="" width="113" height="144" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/android" rel="attachment wp-att-1043"><img class="alignleft size-full wp-image-1043" title="Android" src="http://robtiffany.com/wp-content/uploads/2011/09/Android.png" alt="" width="154" height="153" /></a><a href="http://robtiffany.com/sync-framework/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/attachment/symbian" rel="attachment wp-att-1049"><img class="alignleft size-full wp-image-1049" title="Symbian" src="http://robtiffany.com/wp-content/uploads/2011/09/Symbian.png" alt="" width="152" height="163" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Now some of you might be wondering why you would use a sync technology to move data rather than SOAP or REST web services.  The reason has to do with performance and bandwidth efficiency.  Using SOA, one would retrieve all the data needed to the device in order to see what has changed in SQL Server.  The same goes for uploading data.  Using the Sync Framework Toolkit, only the changes, or deltas, are transmitted over the air.  The boosts performance and reduces bandwidth usage which saves time and money in a world of congested mobile data networks with capped mobile data plans.  You also get a feature called batching, which breaks up the data sent over wireless networks into manageable pieces.  This not only prevents you from blowing out your limited bandwidth, but it also keeps you from using too much RAM memory both on the server and your memory-constrained mobile device.  When combined with conflict resolution and advanced filtering, I&#8217;m sold!</p>
<p>I think you&#8217;ll find the Sync Framework Toolkit to be an immensely valuable component of your MEAP solutions for the enterprise as well as the ones you build for consumers.</p>
<p>Keep Synching,</p>
<p>Rob</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/sync-framework-v4-is-now-open-source-and-ready-to-connect-any-device-to-sql-server-and-sql-azure/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Performance and Memory Management Improvements with Windows Embedded Handheld</title>
		<link>http://robtiffany.com/performance-and-memory-management-improvements-with-windows-embedded-handheld/</link>
		<comments>http://robtiffany.com/performance-and-memory-management-improvements-with-windows-embedded-handheld/#comments</comments>
		<pubDate>Sun, 04 Sep 2011 15:49:39 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Windows Embedded Handheld]]></category>
		<category><![CDATA[.NET Compact Framework]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Device Management]]></category>
		<category><![CDATA[Merge Replication]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[RDA]]></category>
		<category><![CDATA[Remote Data Access]]></category>
		<category><![CDATA[SQL CE]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[Windows Mobile]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=944</guid>
		<description><![CDATA[It should be no surprise that over 80% of enterprise handhelds shipped are running Windows Mobile or Windows Embedded Handheld.  <a href="http://robtiffany.com/performance-and-memory-management-improvements-with-windows-embedded-handheld/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A lot has changed since the launch of Windows Phone in the Fall of 2010.  Microsoft now has a compelling phone platform that targets consumers inside and outside the office.  One thing that that hasn&#8217;t changed is the widespread use of Windows Embedded Handheld to solve tough enterprise mobility problems.  It should be no surprise that over 80% of enterprise handhelds shipped are running Windows Mobile or Windows Embedded Handheld.  They include support for barcode scanning, RFID reading, rugged hardware, every type of wireless, full device encryption, complete over-the-air software distribution and device managment support, FIPS compliance, and both capacitive touch and stylus operation.  On the application platform side of the equation, they have rich support for WinForm development using Visual Studio and the .NET Compact Framework, C++ and a full-featured database with built-in sync capabilities via SQL Server Compact.  They can easily communicate with WCF SOAP and REST web services running on Windows Servers on-premise or with Azure in the cloud.  Support for Merge Replication means faster time to market to get device synchronizing with SQL Server with almost no coding.</p>
<p><a href="http://robtiffany.com/windows-embedded-handheld/performance-and-memory-management-improvements-with-windows-embedded-handheld/attachment/motorola-es400" rel="attachment wp-att-951"><img class="alignleft size-medium wp-image-951" title="Windows Embedded Handheld" src="http://robtiffany.com/wp-content/uploads/2011/09/motorola-es400-144x300.jpg" alt="" width="144" height="300" /></a><a href="http://robtiffany.com/windows-embedded-handheld/performance-and-memory-management-improvements-with-windows-embedded-handheld/attachment/pp-psion-teklogix-12-6-10" rel="attachment wp-att-978"><img class="alignleft size-medium wp-image-978" title="pp-Psion-Teklogix-12-6-10" src="http://robtiffany.com/wp-content/uploads/2011/09/pp-Psion-Teklogix-12-6-10-183x300.jpg" alt="" width="183" height="300" /></a><a href="http://robtiffany.com/windows-embedded-handheld/performance-and-memory-management-improvements-with-windows-embedded-handheld/attachment/dolphin" rel="attachment wp-att-976"><img class="alignleft size-medium wp-image-976" title="dolphin" src="http://robtiffany.com/wp-content/uploads/2011/09/dolphin-163x300.jpg" alt="" width="163" height="300" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://robtiffany.com/windows-embedded-handheld/performance-and-memory-management-improvements-with-windows-embedded-handheld/attachment/intermec" rel="attachment wp-att-979"><img class="alignleft size-medium wp-image-979" title="intermec" src="http://robtiffany.com/wp-content/uploads/2011/09/intermec-140x300.jpg" alt="" width="140" height="300" /></a><a href="http://robtiffany.com/windows-embedded-handheld/performance-and-memory-management-improvements-with-windows-embedded-handheld/attachment/honeywell_99ex" rel="attachment wp-att-977"><img class="alignleft size-medium wp-image-977" title="honeywell_99ex" src="http://robtiffany.com/wp-content/uploads/2011/09/honeywell_99ex-127x300.jpg" alt="" width="127" height="300" /></a></p>
<p>Since Windows Embedded Handheld uses an advanced version of the operating system kernel used by Windows Mobile 6.5.3, many of the techniques and best practices I&#8217;ve taugh customers and developers all over the world still apply.  While it still uses the slotted memory model found in Windows CE 5 with 32 processes and 32 MB of memory per process, you&#8217;ll find that numerous enhancements and tuning has taken place to give your line of business apps more of what they need.  I&#8217;m talking about more memory per process and improved performance.  Therefore, I&#8217;d like you to sit back and watch the video of a presentation I delivered at Tech Ed in Los Angeles a couple of years ago so you can better learn what this mobile platform has to offer in the form of better memory management and improved performance:<br />
<iframe style="width: 512px; height: 384px;" src="http://channel9.msdn.com/Events/TechEd/Europe/2009/MOB401/player?w=512&amp;h=384" frameborder="0" scrolling="no" width="320" height="240"></iframe></p>
<p>A recent Gartner report recommends that organizations should stay with Windows Embedded Handheld as the best mobile platform for enterprise line of business needs.  Great devices are available from OEMs like Intermec, Motorola, Psion, and Honeywell just to name a few.  I hope this video helps you with any memory management or performance issues you may need to deal with in your enterprise mobile apps.</p>
<p>Best Regards,<br />
Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/performance-and-memory-management-improvements-with-windows-embedded-handheld/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server Compact 4.0 Lands on the Web</title>
		<link>http://robtiffany.com/sql-server-compact-4-0-lands-on-the-web/</link>
		<comments>http://robtiffany.com/sql-server-compact-4-0-lands-on-the-web/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 06:31:33 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[.NET Compact Framework]]></category>
		<category><![CDATA[ADO.NET]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[MEAP]]></category>
		<category><![CDATA[Merge Replication]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[RDA]]></category>
		<category><![CDATA[Remote Data Access]]></category>
		<category><![CDATA[SQL CE]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SSCE]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Sync Framework]]></category>
		<category><![CDATA[Synchronize]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows CE]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Windows phones]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=486</guid>
		<description><![CDATA[With the new version 4.0, the little-database-that-could has grown up into a powerful server database ready to take on the web. <a href="http://robtiffany.com/sql-server-compact-4-0-lands-on-the-web/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A decade has passed since I first started using SQL CE on my Compaq iPAQ.  What started as a great upgrade to Pocket Access turned into the ultimate embedded database for Windows CE, the Pocket PC, Windows Mobile and Windows Phones.  The one-two punch of Outlook Mobile synchronizing email with Exchange and SQL Server Compact synchronizing data with SQL Server helped set the mobile enterprise on fire.  In 2005, version 3.0 supported Windows Tablets and progressive enhancements to the code base led to full Windows support on both x86 and x64 platforms.  With the new version 4.0, the little-database-that-could has grown up into a powerful server database ready to take on the web. </p>
<p>We&#8217;ve come a long way and you&#8217;re probably wondering what qualifies this new embedded database to take on the Internet:</p>
<ul>
<li>Native support for x64 Windows Servers</li>
<li>Virtual memory usage has been optimized to ensure the database can support up to 256 open connections &#8211; (Are you actually using 256 pooled connections with your &#8220;Big&#8221; database today?)</li>
<li>Supports databases up to 4 GB in size &#8211; (Feel free to implement your own data sharding scheme<a href="http://robtiffany.com/wp-content/uploads/2011/01/sqlserver_sql_server_2008_logo.png"><img class="alignright size-medium wp-image-496" title="SQL Server Compact" src="http://robtiffany.com/wp-content/uploads/2011/01/sqlserver_sql_server_2008_logo-300x246.png" alt="SQL Server Compact" width="180" height="148" /></a>)</li>
<li>Developed, stress-tested, and tuned to support ASP.NET web applications</li>
<li>Avoids the interprocess communications performance hit by running in-process with your web application</li>
<li>Row-level locking to boost concurrency</li>
<li>Step up to Government + Military grade security SHA2 algorithm to secure data with FIPS compliance</li>
<li>Enhanced data reliability via true atomicity, consistency, isolation, and durability (ACID) support</li>
<li>Transaction support to commit and roll back grouped changes</li>
<li>Full referential integrity with cascading deletes and updates</li>
<li>Support ADO.NET Entity Framework 4 &#8211; (Do I hear WCF Data Services?)</li>
<li>Paging queries are supported via T-SQL syntax to only return the data you actually need</li>
</ul>
<p>Wow, that&#8217;s quite a list!  SQL Server Compact 4.0 databases are easily developed using the new WebMatrix IDE or through Visual Studio 2010 SP1.  I&#8217;m loving the new ASP.NET Web Pages.  It reminds me of the good old days of building web applications with Classic ASP back in the 90&#8242;s with Visual InterDev and Homesite.</p>
<p>What about Mobility?</p>
<p>Since SQL Server Compact owes its heritage to mobile and embedded versions of Windows, you might be wanting to know what our story is there.  The good news is that you can build and deploy v4.0 databases on Windows XP, Windows Vista, and Windows 7.  If you want to implement an occasionally-connected solution that utilizes the Sync Framework, Remote Data Access (RDA), or Merge Replication, you&#8217;ll need to stick with SQL Server Compact 3.5 SP2.  Time and resource-constraints prevented the Compact team from enabling these features.  Luckily, single-user WPF/WinForms database applications running on Windows Slates, laptops and Windows Embedded Handheld devices will work just fine with the v3.5 SP2 runtime.  Get a jumpstart with this by pickup up &#8220;Enterprise Data Synchronization with Microsoft SQL Server 2008 and SQL Server Compact 3.5 Mobile Merge Replication&#8221; at   <a href="http://www.amazon.com/Enterprise-Synchronization-Microsoft-Compact-Replication/dp/0979891213/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1281715114&amp;sr=1-1">http://www.amazon.com/Enterprise-Synchronization-Microsoft-Compact-Replication/dp/0979891213/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1281715114&amp;sr=1-1</a> to start building those MEAP solutions.</p>
<p>With the tidal wave of Windows Slates hitting the market, a secure, powerful mobile database that allows users to work offline and syncs with SQL Server is definitely going to be a hot item!</p>
<p>So run, don&#8217;t walk to the Microsoft Download site to download the Next-Gen database for the web:</p>
<p><a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=033cfb76-5382-44fb-bc7e-b3c8174832e2">http://www.microsoft.com/downloads/en/details.aspx?FamilyID=033cfb76-5382-44fb-bc7e-b3c8174832e2</a></p>
<p>If you need to support occasionally-connected mobile applications with sync capabilities on muliple Windows platforms, download SQL Server Compact 3.5 SP2:</p>
<p><a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=e497988a-c93a-404c-b161-3a0b323dce24">http://www.microsoft.com/downloads/en/details.aspx?FamilyID=e497988a-c93a-404c-b161-3a0b323dce24</a></p>
<p>Keep Syncing,</p>
<p>Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/sql-server-compact-4-0-lands-on-the-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reducing SQL Server Sync I/O Contention :: Tip 3</title>
		<link>http://robtiffany.com/reducing-sql-server-sync-io-contention-tip-3/</link>
		<comments>http://robtiffany.com/reducing-sql-server-sync-io-contention-tip-3/#comments</comments>
		<pubDate>Mon, 10 Jan 2011 23:43:35 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Merge Replication]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[RDA]]></category>
		<category><![CDATA[Remote Data Access]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL CE]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[SSCE]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Sync Framework]]></category>
		<category><![CDATA[Synchronize]]></category>
		<category><![CDATA[Windows Phone 7]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=475</guid>
		<description><![CDATA[Uniqueness is a key factor when synchronizing data between SQL Server/Azure and multiple endpoints like Slates and Smartphones.  With data simultaneously created and updated on servers and clients, ensuring rows are unique to avoid key collisions is critical.  As you know, each row is uniquely identified by its Primary Key. <a href="http://robtiffany.com/reducing-sql-server-sync-io-contention-tip-3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h5>GUIDs and Clustered Indexes</h5>
<p>Uniqueness is a key factor when synchronizing data between SQL Server/Azure and multiple endpoints like Slates and Smartphones.  With data simultaneously created and updated on servers and clients, ensuring rows are unique to avoid key collisions is critical.  As you know, each row is uniquely identified by its Primary Key.</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2011/01/key.png"><img class="alignleft size-medium wp-image-476" title="Primary Key" src="http://robtiffany.com/wp-content/uploads/2011/01/key-300x156.png" alt="Primary Key" width="300" height="156" /></a></p>
<p>When creating Primary Keys, it’s common to use a compound key based on things like account numbers, insert time and other appropriate business items.  It’s even more popular to create Identity Columns for the Primary Key based on an Int or BigInt data type based on what I see from my customers.  When you designate a column(s) to be a Primary Key, SQL Server automatically makes it a Clustered Index.  Clustered indexes are faster than normal indexes for sequential values because the B-Tree leaf nodes are the actual data pages on disk, rather than just pointers to data pages.</p>
<p>While Identity Columns work well in most database situations, they often break down in a data synchronization scenario since multiple clients could find themselves creating new rows using the same key value.  When these clients sync their data with SQL Server, key collisions would occur.  Merge Replication includes a feature that hands out blocks of Identity Ranges to each client to prevent this. </p>
<p>When using other Microsoft sync technologies like the Sync Framework or RDA, no such Identity Range mechanism exists and therefore I often see GUIDs utilized as Primary Keys to ensure uniqueness across all endpoints.  In fact, I see this more and more with Merge Replication too since SQL Server adds a GUID column to the end of each row for tracking purposes anyway.  Two birds get killed with one Uniqueidentifier stone. </p>
<p>Using the Uniqueidentifier data type is not necessarily a bad idea.  Despite the tradeoff of reduced join performance vs. integers, the solved uniqueness problem allows sync pros to sleep better at night.  The primary drawback with using GUIDs as Primary Keys goes back to the fact that SQL Server automatically gives those columns a Clustered Index.</p>
<p><strong>I thought Clustered Indexes were a good thing?</strong></p>
<p>They are a good thing when the values found in the indexed column are sequential.  Unfortunately, GUIDs generated with the default NewId() function are completely random and therefore create a serious performance problem.  All those mobile devices uploading captured data means lots of Inserts for SQL Server.  Inserting random key values like GUIDs can cause fragmentation in excess of 90% because new pages have to be allocated with rows pushed to the new page in order to insert the record on the existing page.  This performance-killing, space-wasting page splitting wouldn’t happen with sequential Integers or Datetime values since they actually help fill the existing page.</p>
<p> <strong>What about NEWSEQUENTIALID()?</strong></p>
<p>Generating your GUIDs on SQL Server with this function will dramatically reduce fragmentation and wasted space since it guarantees that each GUID will be sequential.  Unfortunately, this isn’t bulletproof.  If your Windows Server is restarted for any reason, your GUIDs may start from a lower range.  They’ll still be globally unique, but your fragmentation will increase and performance will decrease.  Also keep in mind that all the devices synchronizing with SQL Server will be creating their own GUIDs which blows the whole NEWSEQUENTIALID() strategy out of the water.</p>
<h5>Takeaway</h5>
<p>If you’re going to use the Uniqueidentifier data type for your Primary Keys and you plan to sync your data with RDA, the Sync Framework or Merge Replication, ensure that <strong>Create as Clustered == No</strong> for better performance.  You’ll still get fragmentation, but it will be closer to the ~30% range instead almost 100%.</p>
<p>Keep synching</p>
<p>Rob</p>
<div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:bf960cbd-b9a9-41b8-9652-5bf27b02ff01">Technorati Tags: <a rel="tag" href="http://technorati.com/tags/SQL+Server">SQL Server</a>,<a rel="tag" href="http://technorati.com/tags/SQL+Server+Compact">SQL Server Compact</a>,<a rel="tag" href="http://technorati.com/tags/Sync">Sync</a>,<a rel="tag" href="http://technorati.com/tags/GUID">GUID</a>,<a rel="tag" href="http://technorati.com/tags/Clustered+Index">Clustered Index</a>,<a rel="tag" href="http://technorati.com/tags/Microsoft">Microsoft</a>,<a rel="tag" href="http://technorati.com/tags/Windows">Windows</a>,<a rel="tag" href="http://technorati.com/tags/SQL+Azure">SQL Azure</a>,<a rel="tag" href="http://technorati.com/tags/MEAP">MEAP</a></div>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/reducing-sql-server-sync-io-contention-tip-3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Reducing SQL Server I/O Contention during Sync :: Tip 2</title>
		<link>http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-2/</link>
		<comments>http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-2/#comments</comments>
		<pubDate>Sat, 08 Jan 2011 01:07:07 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Isolated Storage]]></category>
		<category><![CDATA[Merge Replication]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[RDA]]></category>
		<category><![CDATA[Remote Data Access]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Slate]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL CE]]></category>
		<category><![CDATA[SQL Compact]]></category>
		<category><![CDATA[SQL Compact 4]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[SQLCE]]></category>
		<category><![CDATA[SSCE]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Sync Framework]]></category>
		<category><![CDATA[Synchronize]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Windows phones]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=455</guid>
		<description><![CDATA[All DBAs know that Joining tables on non-indexed columns is the most expensive operation SQL Server can perform.   <a href="http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h5>Indexing Join Columns</h5>
<p>In my last Sync/Contention post, I beat up on a select group of SAN administrators who aren&#8217;t willing to go the extra mile to optimize the very heart of their organization, SQL Server.  You guys know who you are.</p>
<p>This time, I want to look at something more basic, yet often overlooked.<a href="http://robtiffany.com/wp-content/uploads/2011/01/emc_symmetrix_vmax-1024x571.jpg"><img class="size-full wp-image-458 alignnone" title="Database Storage" src="http://robtiffany.com/wp-content/uploads/2011/01/emc_symmetrix_vmax-1024x571.jpg" alt="" width="640" height="356" /></a></p>
<p>All DBAs know that Joining tables on non-indexed columns is the most expensive operation SQL Server can perform.  Amazingly, I run into this problem over and over with many of my customers.  Sync technologies like the Sync Framework, RDA and Merge Replication allow for varying levels of server-side filtering.  This is a popular feature used to reduce the size of the tables and rows being downloaded to Silverlight Isolated Storage or SQL Server Compact. </p>
<p>It&#8217;s also a performance killer when tables and columns participating in a Join filter are not properly indexed.  Keeping rows locked longer than necessary creates undue blocking and deadlocking.  It also creates unhappy slate and smartphone users who have to wait longer for their sync to complete.</p>
<p>Do yourselft a favor and go take a look at all the filters you&#8217;ve created and makes sure that you have indexes on all those Joined columns.</p>
<p>Keep synching,</p>
<p>Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reducing SQL Server I/O Contention during Sync :: Tip 1</title>
		<link>http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-1/</link>
		<comments>http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-1/#comments</comments>
		<pubDate>Thu, 06 Jan 2011 06:16:55 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[I/O]]></category>
		<category><![CDATA[LUN]]></category>
		<category><![CDATA[Merge Replication]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[RAID]]></category>
		<category><![CDATA[Remote Data Access]]></category>
		<category><![CDATA[SAN]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[SSCE]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Sync Framework]]></category>
		<category><![CDATA[Synchronize]]></category>
		<category><![CDATA[tempdb]]></category>
		<category><![CDATA[Transaction Logs]]></category>
		<category><![CDATA[Windows Mobile]]></category>
		<category><![CDATA[Windows Phone 7]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=447</guid>
		<description><![CDATA[The act of tracking changes made by each SQL Server Compact or Silverlight sync subscriber can cause a lot of locking and blocking on the server. <a href="http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-1/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h5>RAID</h5>
<p>Sync technologies like Merge Replication and the Sync Framework track changes on SQL Server using triggers, stored procedures and special tracking tables.  The act of tracking changes made by each SQL Server Compact or Silverlight sync subscriber can cause a lot of locking and blocking on the server.  This diminishes performance and sometimes leads to deadlocks. <a href="http://robtiffany.com/wp-content/uploads/2011/01/x3_wss-storageserver2_2.jpg"><img class="alignleft size-full wp-image-450" title="SAN Storage" src="http://robtiffany.com/wp-content/uploads/2011/01/x3_wss-storageserver2_2.jpg" alt="SAN Storage" width="540" height="186" /></a></p>
<p>Therefore, don&#8217;t listen to your SAN administrator when he says the RAID 5 will do.  RAID 1 or 10 must always be used for all databases, tempdb, and transaction logs.  Furthermore, each of these database objects must be placed on their own dedicated RAID arrays.  No sharing!  Remembers, as a DBA and sync expert, knowledge of SAN configuration must always be part of your skillset.</p>
<p>Keeping synching,</p>
<p>Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/reducing-sql-server-io-contention-during-sync-tip-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows Phone 7 Line of Business App Dev :: Improving the In-Memory Database</title>
		<link>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-improving-the-in-memory-database/</link>
		<comments>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-improving-the-in-memory-database/#comments</comments>
		<pubDate>Sat, 27 Nov 2010 07:19:51 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[AutoFlush]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Chage-tracking]]></category>
		<category><![CDATA[Column]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[DataContractJsonSerializer]]></category>
		<category><![CDATA[DML]]></category>
		<category><![CDATA[Isolated Storage]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[ObservableCollection]]></category>
		<category><![CDATA[Occasionally-connected]]></category>
		<category><![CDATA[RDA]]></category>
		<category><![CDATA[Remote Data Access]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Row]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Singleton]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[SQLCE]]></category>
		<category><![CDATA[Table]]></category>
		<category><![CDATA[Visual Studio 2010]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[Windows Azure]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[XmlSerializer]]></category>

		<guid isPermaLink="false">http://robtiffany.com/windows-phone-7/windows-phone-7-line-of-business-app-dev-improving-the-in-memory-database</guid>
		<description><![CDATA[About a month ago, I wrote an article intended to help you fill some of the gaps left by the missing SQL Server Compact database.&#160; Since your Windows Phone 7 Silverlight app is consuming an ObservableCollection of objects streaming down &#8230; <a href="http://robtiffany.com/windows-phone-7-line-of-business-app-dev-improving-the-in-memory-database/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>About a month ago, I wrote an article intended to help you fill some of the gaps left by the missing <strong>SQL Server Compact</strong> database.&#160; Since your <strong>Windows Phone 7 Silverlight</strong> app is consuming an <strong>ObservableCollection</strong> of objects streaming down from <strong>Windows Azure</strong> and <strong>SQL Azure</strong>, it makes sense to organize those objects in a database-like format that’s easy to work with.&#160; If you’ve ever worked with <strong>Remote Data Access (RDA)</strong> in the past, the notion of <strong>pre-fetching</strong> multiple tables to work with locally should look familiar.&#160; </p>
<p>In this case, each <strong>ObservableCollection</strong> represents a table, each object represents a row, and each object property represents a column.&#160; I had you create a <strong>Singleton</strong> class to hold all these objects in memory to serve as the database.&#160; The fact that Silverlight supports <strong>Language Integrated Query (LINQ)</strong> means that you can use <strong>SQL-like statements</strong> to work with the multiple, ObservableCollections of objects.&#160; </p>
<p>If you’re wondering why I have you cache everything in memory in a Singleton, there’s a few reasons.&#160; For starters, it makes it easy to query everything with <strong>LINQ</strong> with the fastest performance possible for single and multi-table JOINs.&#160; Secondly, I don’t represent a <strong>Microsoft</strong> product group and therefore wouldn’t engineer an unsupported provider that can query subsets of serialized data from files residing in <strong>Isolated Storage</strong>.&#160; Finally, I don’t want you to accidentally find yourself with <strong>multiple instances</strong> of the same ObservableCollection when pulling data down from <strong>Azure</strong> or loading it from Isolated Storage.&#160; Forcing everything into a Singleton prevents you <strong>wasting memory</strong> or updating objects in the wrong instance of an ObservableCollection.&#160; An inconsistent database is not a good thing.&#160; Don’t worry, you can control which tables are loaded into memory.</p>
<p>So what is this article all about and what are the <strong>“improvements”</strong> I’m talking about?</p>
<p>This time around, I’m going to focus on <strong>saving</strong>, <strong>loading</strong> and <strong>deleting</strong> the <strong>serialized</strong> ObservableCollections from Isolated Storage.&#160; In that last article, I showed you how to serialize/de-serialize the ObservableCollections to and from Isolated Storage using the <strong>XmlSerializer</strong>.&#160; This made it easy for you to save each table to its own XML file which sounds pretty cool. </p>
<p>So what’s wrong with this?</p>
<p>Saving anything as <strong>XML</strong> means that you’re using the largest, most verbose form of serialization.&#160; After hearing me preach about the virtues of doing <strong>SOA</strong> with <strong>WCF REST + JSON</strong>, using the <strong>XmlSerializer</strong> probably seems out of place.&#160; Luckily, the <strong>DataContractJsonSerializer</strong> supported by <strong>Silverlight</strong> on <strong>Windows Phone 7</strong> gives you the most <strong>efficient wire protocol</strong> for data-in-transit can also be used to save those same .NET objects to Isolated Storage.&#160; So the first improvement in this article comes from shrinking the size of the tables and improving the efficiency of the serialization/de-serializing operations to Isolated Storage using out-of-the-box functionality.&#160; </p>
<p>While going from XML to JSON for your serializing might be good enough, there’s another improvement in the way you write the code that will make this much easier to implement for your own projects.&#160; A look back to the previous article reveals a <strong>tight coupling</strong> between the tables that needed to be saved/loaded and the code needed to make that happen.&#160; This meant that you would have to create a <strong>SaveTable</strong> and <strong>LoadTable</strong> method for each table that you wanted to retrieve from <strong>Azure</strong>.&#160; The new code you’re about to see is <strong>generic</strong> and allows you to use a single SaveTable and LoadTable method even if you decide to download 100 tables.</p>
<p>Enough talk already, let’s see some code.&#160; Launch your <strong>ContosoCloud</strong> solution in <strong>Visual Studio</strong> and open <strong>Database.cs</strong>.&#160; I want you to overwrite the existing code with the code shown below:</p>
<p><font size="1"><strong>using System;       <br />using System.Net;        <br />using System.Windows;        <br />using System.Collections.Generic;        <br />using System.Collections.ObjectModel;        <br />using System.IO.IsolatedStorage;        <br />using System.Runtime.Serialization.Json;</strong></font></p>
<p><font size="1"><strong>namespace ContosoPhone       <br />{        <br />&#160;&#160;&#160; sealed class Database        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Declare Instance        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; private static readonly Database instance = new Database();</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Private Constructor       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; private Database() { }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //The entry point into this Database       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public static Database Instance        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; get        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return instance;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Serialize ObservableCollection to JSON in Isolated Storage       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void SaveTable&lt;T&gt;(T tableToSave, string tableName)        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (tableToSave != null)        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFileStream stream = store.CreateFile(tableName + &quot;.txt&quot;))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; serializer.WriteObject(stream, tableToSave);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new Exception(&quot;Table is empty&quot;);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Deserialize ObservableCollection from JSON in Isolated Storage       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public T LoadTable&lt;T&gt;(T tableToLoad, string tableName)        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (store.FileExists(tableName + &quot;.txt&quot;))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFileStream stream = store.OpenFile(tableName + &quot;.txt&quot;, System.IO.FileMode.Open))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (T)serializer.ReadObject(stream);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new Exception(&quot;Table not found&quot;);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Delete ObservableCollection from Isolated Storage       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void DropTable(string tableName)        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (store.FileExists(tableName + &quot;.txt&quot;))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; store.DeleteFile(tableName + &quot;.txt&quot;);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new Exception(&quot;Table not found&quot;);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Declare Private Table Variables        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; private ObservableCollection&lt;Customer&gt; customerTable = null;</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Customer Table       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public ObservableCollection&lt;Customer&gt; Customers        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; get { return customerTable; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; set { customerTable = value; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160; }        <br />}        <br /></strong></font></p>
<p>&#160;</p>
<p>Looking from top to bottom, the first change you’ll notice is the new <strong>SaveTable</strong> method where you pass in the desired <strong>ObservableCollection</strong> and <strong>table name</strong> in order to serialize it as <strong>JSON</strong> using the <strong>DataContractJsonSerializer</strong>.&#160; The next method down the list is <strong>LoadTable</strong> where you pass in the same parameters as <strong>SaveTable</strong> but you get back a <strong>de-serialized</strong> ObservableCollection.&#160; The last new method in the Database Singleton is <strong>DropTable</strong> which simply <strong>deletes</strong> the serialized table from Isolated Storage if you don’t need it anymore.</p>
<p>So how do you call this code?</p>
<p>Bring up <strong>MainPage.xaml.cs</strong>, and find the click event for <strong>Save button</strong>.&#160; Delete the existing <strong>XmlSerializer</strong> code and replace it with the following:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; Database.Instance.SaveTable&lt;ObservableCollection&lt;Customer&gt;&gt;(Database.Instance.Customers, &quot;Customers&quot;);        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>The code above shows you how to call the <strong>SaveTable</strong> method in the Singleton with the appropriate syntax to pass in the ObservableCollection type as well as actual ObservableCollection value and name.</p>
<p>Now find the click event for the <strong>Load button</strong>, delete the existing code and paste in the following:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; Database.Instance.Customers = Database.Instance.LoadTable&lt;ObservableCollection&lt;Customer&gt;&gt;(Database.Instance.Customers, &quot;Customers&quot;);        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>This code looks pretty much the same as the <strong>SaveTable</strong> code except that you set <strong>Database.Instance.Customers</strong> equal to the return value from the method.&#160; For completeness sake, drop another button on <strong>MainPage.xaml</strong> and call it <strong>Drop</strong>.&#160; In its click event, paste in the following code:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; Database.Instance.DropTable(&quot;Customers&quot;);        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>For this code, just pass in the name of the table you want to delete from Isolated Storage and it’s gone.</p>
<p>It’s time to hit F5 so you can see how things behave.</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/11/phone7.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="phone7" border="0" alt="phone7" src="http://robtiffany.com/wp-content/uploads/2010/11/phone7_thumb.png" width="258" height="484" /></a></p>
<p>When your app comes to life in the emulator, I want you to exercise the system by <strong>Getting</strong>, <strong>Adding</strong>, <strong>Updating</strong> and <strong>Deleting</strong> Customers.&#160; In between, I want you to tap the Save button,<strong> close the app</strong>, reload the app and tap the Load button and then View Customers to ensure you’re seeing the list of Customers you expect.&#160; Keep in mind that when you Save, you <strong>overwrite the previously saved table</strong>.&#160; Likewise, when you Load, you <strong>overwrite the current in-memory ObservableCollection</strong>.&#160; Additionally, Saving, Loading, and Dropping tables that don’t exist should throw an appropriate error message.</p>
<p>So what’s the big takeaway for these tweaks I’ve made to the in-memory database?</p>
<p>While switching serialization from <strong>XML</strong> to <strong>JSON</strong> is a great improvement in size and efficiency, I truly believe that making the SaveTable and LoadTable methods <strong>generic</strong> and <strong>reusable</strong> will <strong>boost developer productivity</strong>.&#160; The new ease with which you can Save and Load 1, 10 or even 1,000 tables makes this more attractive to mobile developers that need to work with local data.</p>
<p>So where do we go from here?</p>
<p>You now have some of the basic elements of a database on <strong>Windows Phone 7</strong>.&#160; You don’t have <strong>ACID</strong> support, <strong>indexes</strong>, <strong>stored procedures</strong> or <strong>triggers</strong> but you have a foundation to build on.&#160; So what should be built next?&#160; </p>
<p>To help ensure <strong>database consistency</strong>, I would add an <strong>AutoFlush</strong> feature next.&#160; <strong>SQL Server Compact</strong> flushes its data to disk every 10 seconds and there’s nothing to prevent you from using the SaveTable method to do the same.&#160; A timer set to fire at a user-specified interval that <strong>iterates</strong> through all the ObservableCollections and saves them will help keep your data safe from <strong>battery loss</strong> and unforeseen system failures.&#160; The fact that your app can be <strong>tombstoned</strong> at any moment when a user taps the Back button makes an AutoFlush feature even more important.</p>
<p>Anything else?</p>
<p>At the beginning of this article I mentioned <strong>RDA</strong> which is a simple form of data synchronization.&#160; It’s simple because it only tracks changes on the client but not the server.&#160; To find out what’s new or changed on the server, RDA requires local tables on the device to be dropped and then re-downloaded from SQL Server.&#160; With the system I’ve built and described throughout this series of articles, we already have this brute force functionality.&#160; So what’s missing is <strong>client-side change tracking</strong>.&#160; To do this, I would need to add code that fires during INSERTS, UPDATES, and DELETES and then writes the appropriate information to local tracking tables.&#160; To push those changes back to <strong>SQL Azure</strong>, appropriate code would need to call <strong>WCF REST + JSON</strong> Services that execute <strong>DML</strong> code on <strong>Windows Azure</strong>.</p>
<p>I hope with the improvements I’ve made to the in-memory database in this article, you’ll feel even more empowered to build <strong>occasionally-connected</strong> Windows Phone 7 solutions for consumers and the enterprise.</p>
<p>Keep coding!</p>
<p>-Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-improving-the-in-memory-database/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Windows Phone 7 Demo Fest Tech Ed Video</title>
		<link>http://robtiffany.com/windows-phone-7-demo-fest-tech-ed-video/</link>
		<comments>http://robtiffany.com/windows-phone-7-demo-fest-tech-ed-video/#comments</comments>
		<pubDate>Mon, 15 Nov 2010 21:21:55 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Exchange Server]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Sharepoint]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=398</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><object class="player" width="645" height="363" type="application/x-silverlight-2" data="data:application/x-silverlight-2,"><param value="http://www.msteched.com/ClientBin/players/VideoPlayer2009_03_27.xap" name="source" /><param value="m=http://ecn.channel9.msdn.com/o9/te/Europe/2010/wmv/wph103-lnc.wmv,thumbnail=http://www.msteched.com/Skins/TechEdOnline/Styles/images/DefaultPlayerBackground.png,autohide=true,showembed=true" name="initParams" /><param value="#00000000" name="background" /><param name="minRuntimeVersion" value="3.0.50106.0" /><param name="windowless" value="true" /><param name="enableGPUAcceleration" value="true" /><param name="autoUpgrade" value="true" /><a href="http://go.microsoft.com/fwlink/?LinkID=149156&#038;v=3.0.50106.0" style="text-decoration:none"><br />
	  <img src="http://www.msteched.com/Skins/TechEdOnline/Styles/images/NoSilverlight.jpg" alt="Get Microsoft Silverlight" style="border-style:none"/><br />
  </a><br />
</object></p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/windows-phone-7-demo-fest-tech-ed-video/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://ecn.channel9.msdn.com/o9/te/Europe/2010/wmv/wph103-lnc.wmv" length="139729637" type="video/asf" />
		</item>
		<item>
		<title>Windows Phone 7 Line of Business App Dev :: Working with an In-Memory Database</title>
		<link>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-working-with-an-in-memory-database/</link>
		<comments>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-working-with-an-in-memory-database/#comments</comments>
		<pubDate>Fri, 05 Nov 2010 14:07:25 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Emulator]]></category>
		<category><![CDATA[IEnumerable]]></category>
		<category><![CDATA[Isolated Storage]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[ObservableCollection]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[Visual Studio 2010]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[Windows Azure]]></category>
		<category><![CDATA[XmlSerializer]]></category>

		<guid isPermaLink="false">http://robtiffany.com/windows-phone-7/windows-phone-7-line-of-business-app-dev-working-with-an-in-memory-database</guid>
		<description><![CDATA[In my last article of this series, you finally got to consume wireless-friendly WCF REST + JSON Services from both Windows Server and Windows Azure with data coming from SQL Server/SQL Azure.&#160; You now have an ObservableCollection of Customer objects &#8230; <a href="http://robtiffany.com/windows-phone-7-line-of-business-app-dev-working-with-an-in-memory-database/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In my last article of this series, you finally got to consume <strong>wireless-friendly</strong> <strong>WCF REST + JSON Services</strong> from both <strong>Windows Server</strong> and <strong>Windows Azure</strong> with data coming from <strong>SQL Server/SQL Azure</strong>.&#160; You now have an <strong>ObservableCollection</strong> of Customer objects residing in a <strong>Singleton</strong> on your <strong>Windows Phone 7</strong> device.&#160; This Singleton looks similar to an in-memory database and the Customers property works like a <strong>table</strong>.</p>
<p>So now what?</p>
<p>If you’re like me, you probably want to display the list of <strong>Customers</strong> in the <strong>UI</strong>.&#160; You might also want to perform other local operations against this data store.&#160; You could add a new Customer and update or even delete an existing one.</p>
<p>I’m going to apologize in advance for not doing the <strong>MVVM</strong> thing that everyone seems to be into these days and get right to the point. Drag a button on to <strong>MainPage.xaml</strong> and call it <strong>View Customers</strong>.&#160; While you’re at it, drag a listbox below the button and name it <strong>listBoxCustomers</strong>.&#160; Double-click on this Button and add the following code to the click event:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; if (Database.Instance.Customers != null)        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; listBoxCustomers.DisplayMemberPath = &quot;Name&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; listBoxCustomers.ItemsSource = Database.Instance.Customers;        <br />&#160;&#160;&#160; }        <br />&#160;&#160;&#160; else        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; MessageBox.Show(&quot;The Customer Table is Empty&quot;);        <br />&#160;&#160;&#160; }        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>In the simple code above, you set the listbox’s <strong>ItemsSource</strong> equal to the Customer collection in the Database Singleton and set the <strong>DisplayMemberPath</strong> property equal to the <strong>Name</strong> property of the Customer objects.</p>
<p>Hit F5 to start debugging this <strong>Windows Phone 7 + Azure</strong> solution.&#160; As usual, a web page and the emulator will launch.&#160; Tap the <strong>Get Customers</strong> button to pull the Customer data back from the <strong>WCF REST</strong> service.&#160; Next, tap on the <strong>View Customers</strong> button to display the list of Customers from the in-memory database as shown in the picture below:</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/11/phone1.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="phone1" border="0" alt="phone1" src="http://robtiffany.com/wp-content/uploads/2010/11/phone1_thumb.png" width="258" height="484" /></a></p>
<p>Now it’s time to add a new Customer so drop a button underneath the listbox and call it <strong>Add Customer</strong>.&#160; Creating a new Customer object requires setting values for 8 properties.&#160; Instead of having you add 8 textboxes to type in the info, I’ll keep in simple and let you add it in code.&#160; In the click event of the button, paste in the code you see below:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; if (Database.Instance.Customers != null)        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Customer customer = new Customer();        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.CustomerId = 5;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.DistributionCenterId = 1;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.RouteId = 1;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.Name = &quot;ABC Corp&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.StreetAddress = &quot;555 Market Street&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.City = &quot;Seattle&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.StateProvince = &quot;WA&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; customer.PostalCode = &quot;98987&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Database.Instance.Customers.Add(customer);        <br />&#160;&#160;&#160; }        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>After setting all the <strong>properties (Columns),</strong> you add the <strong>Customer object (Row)</strong> to the <strong>Customers property (Table)</strong>, in the <strong>Singleton Database</strong>.&#160; Hit F5, tap the <strong>Get Customers</strong> button, tap the <strong>View Customers</strong> button and then tap the <strong>Add Customer</strong> button.&#160; Through the magic of simple<strong> data-binding</strong>, you should see the new “ABC Corp” show up in the listbox as shown below:</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/11/phone2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="phone2" border="0" alt="phone2" src="http://robtiffany.com/wp-content/uploads/2010/11/phone2_thumb.png" width="257" height="484" /></a></p>
<p>Now that you’ve added a new Customer, it’s time to update it because the president of the company decided to change the name.&#160; Drag a new button and drop it underneath the <strong>Add Customer</strong> button.&#160; Call it <strong>Update Customer</strong> and in it’s click event, paste in the following code:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; if (Database.Instance.Customers != null)        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach (Customer c in Database.Instance.Customers)        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (c.Equals((Customer)listBoxCustomers.SelectedItem))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; c.Name = &quot;XYZ Inc&quot;;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160; }        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>The code above loops through the Customers ObservableCollection until it finds a match for the item that’s been selected in the listbox.&#160; When it finds that match, it updates the <strong>Name</strong> property to “XYZ Inc” which will automatically update what the user views in the listbox.</p>
<p>Hit F5, tap the <strong>Get Customers</strong> button, tap the <strong>View Customers</strong> button and then tap the <strong>Add Customer</strong> button.&#160; Now tap on <strong>“ABC Corp”</strong> in the listbox to highlight it.&#160; Clicking the<strong> Update Customer</strong> button will change it before your eyes.</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/11/phone3.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="phone3" border="0" alt="phone3" src="http://robtiffany.com/wp-content/uploads/2010/11/phone3_thumb.png" width="255" height="484" /></a></p>
<p>It turns out that “XYZ Inc” went out of business because the president was an idiot so you need to delete it.&#160; Guess what, you need yet another button beneath the <strong>Update Customer</strong> button.&#160; Call it <strong>Delete Customer</strong> and in it’s click event, paste in the following code:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; if (Database.Instance.Customers != null)        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Database.Instance.Customers.Remove((Customer)listBoxCustomers.SelectedItem);        <br />&#160;&#160;&#160; }        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>In the code above, the Customer object that matches the item selected in the listbox is removed from the Customers ObservableCollection.&#160; Pretty simple stuff in this case.</p>
<p>To find out for sure, hit F5, tap the <strong>Get Customers</strong> button, tap the<strong> View Customers</strong> button and then tap the <strong>Add Customer</strong> button.&#160; Now tap on <strong>“ABC Corp”</strong> in the listbox to highlight it.&#160; Clicking the <strong>Update Customer</strong> button will change it to<strong> “XYZ Inc.”</strong>&#160; Highlighting “XYZ Inc” and clicking the <strong>Delete Customer</strong> button will cause this defunct company to disappear as shown below:</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/11/phone4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="phone4" border="0" alt="phone4" src="http://robtiffany.com/wp-content/uploads/2010/11/phone4_thumb.png" width="261" height="484" /></a></p>
<p>Now suppose you only want to display the Customers from <strong>Seattle</strong> and not the <strong>Eastside</strong>.&#160; A little <strong>LINQ</strong> will do the trick here.&#160; Drag and drop a new button called <strong>Seattle</strong> next to the<strong> Test Uri</strong> button and paste the following code in the click event:</p>
<p><font size="1"><strong>if (Database.Instance.Customers != null)       <br />{        <br />&#160;&#160;&#160; IEnumerable&lt;Customer&gt; customers = from customer in Database.Instance.Customers        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; where customer.DistributionCenterId == 1        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; select customer;        <br />&#160;&#160;&#160; listBoxCustomers.DisplayMemberPath = &quot;Name&quot;;        <br />&#160;&#160;&#160; listBoxCustomers.ItemsSource = customers;        <br />}        <br />else        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(&quot;The Driver Table is Empty&quot;);        <br />}</strong></font></p>
<p>In the code above, I set an<strong> IEnumerable&lt;Customer&gt;</strong> variable equal to the <strong>Customers table</strong> where the <strong>DistributionCenterId is equal to 1</strong>.&#160; Since the DistributionCenter #1 serves the Seattle area, I know the listbox will be filled with just <strong>Adventure Works LLC</strong> and <strong>City Power &amp; Light</strong>.&#160; Start debugging and test it for yourself.</p>
<p>The last thing you need to do with local data is store it offline since you can’t always count on the network being there.&#160; Luckily we’ve got <strong>Isolated Storage</strong> to serialize stuff.&#160; In order to work with Isolated Storage, I need you to add <strong>using System.IO.IsolatedStorage;</strong> at the top of the class.&#160; Since in this example I’ll demonstrate<strong> XML Serialization</strong> of the Customers ObservableCollection, I’ll need you to <strong>add a reference</strong> to <strong>System.Xml.Serialization</strong> and then add <strong>using System.Xml.Serialization;</strong> at the top of the class.&#160; With that plumbing in place, let’s write some actual code.</p>
<p>Drag and drop another button called <strong>Save</strong> next to the <strong>Get Customers</strong> button and paste the following code in the click event:</p>
<p><font size="1"><strong>if (Database.Instance.Customers != null)       <br />{        <br />&#160;&#160;&#160; using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFileStream stream = store.CreateFile(&quot;Customers.xml&quot;))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection&lt;Customer&gt;));        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; serializer.Serialize(stream, Database.Instance.Customers);</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }       <br />&#160;&#160;&#160; }        <br />}</strong></font></p>
<p>In the code above, you use the combination of <strong>IsolatedStorageFile</strong> and <strong>IsolatedStorageFileStream</strong> to write data to Isolated Storage.&#160; In this case, you’re going to create an XML file to save the Customers ObservableCollection of Customer objects.&#160; Remember back in the 80’s when databases used to save each table as an individual file?&#160; I’m thinking of DBase III+, FoxPro, and Paradox at the moment.&#160; Anyway, this is exactly what happens here using the power of the XmlSerializer.&#160; Feel free to debug and step through the code to ensure that it executes without error.</p>
<p>To complete the picture, you need to be able to retrieve the Customers ObservableCollection from Isolated Storage and work with the data without ever having to call the <strong>WCF REST</strong> services.&#160; Drag and drop one last button called <strong>Load</strong> next to the<strong> View Customers</strong> button and paste the following code in the click event:</p>
<p><font size="1"><strong>using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())       <br />{        <br />&#160;&#160;&#160; if (store.FileExists(&quot;Customers.xml&quot;))        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; using (IsolatedStorageFileStream stream = store.OpenFile(&quot;Customers.xml&quot;, System.IO.FileMode.Open))        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection&lt;Customer&gt;));        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Database.Instance.Customers = (ObservableCollection&lt;Customer&gt;)serializer.Deserialize(stream);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160; }        <br />}</strong></font></p>
<p>The code above does the reverse of the previous Save code by opening the Customers.xml and <strong>re-hydrating</strong> those objects back into the Customers table using the XmlSerializer.&#160; This is pretty cool stuff.</p>
<p>To make it all real, hit F5 to start debugging this completed mobile project.&#160; When the app loads, tap the <strong>Get Customers</strong> button to retrieve the data and then tap <strong>View Customers</strong> to verify that you can see the data.&#160; Now I want you to tap the <strong>Save</strong> button to serialize the Customers to an XML file in Isolated Storage.&#160; Lastly, I want you to tap on the <strong>Back</strong> button to close the application.</p>
<p>Hit F5 again to fire up the application.&#160; This time, I don’t want you to retrieve the data from <strong>Azure</strong>.&#160; Instead, I want you to tap the <strong>Load</strong> button to <strong>de-serialize</strong> the Customer objects from XML.&#160; Now for the moment of truth.&#160; Tap the <strong>View Customers</strong> button to see if you’re actually working with an <strong>offline database</strong>.&#160; Hopefully, your app will look like the picture below:</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/11/phone5.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="phone5" border="0" alt="phone5" src="http://robtiffany.com/wp-content/uploads/2010/11/phone5_thumb.png" width="267" height="484" /></a></p>
<p><strong>Congratulations!</strong>&#160; You’ve made it to the end of this series of articles on building an <strong>occasionally-connected</strong> <strong>Windows Phone 7</strong> application that works with <strong>WCF REST + JSON Services</strong> in <strong>Windows Azure</strong>.&#160; Furthermore, you’re now pulling data down from <strong>SQL Azure</strong> and you’re working with it locally using a <strong>simple in-memory database</strong> that you built yourself.&#160; I’m hoping that you’ll now feel empowered to go build industrial-strength mobile solutions for your own company or your customers.</p>
<p>Keep coding!</p>
<p>-Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-working-with-an-in-memory-database/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The Windows Phone 7 Mobile Enterprise Application Platform (MEAP) @ Tech Ed Europe 2010</title>
		<link>http://robtiffany.com/the-windows-phone-7-mobile-enterprise-application-platform-meap-tech-ed-europe-2010/</link>
		<comments>http://robtiffany.com/the-windows-phone-7-mobile-enterprise-application-platform-meap-tech-ed-europe-2010/#comments</comments>
		<pubDate>Wed, 03 Nov 2010 18:18:53 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Gartner]]></category>
		<category><![CDATA[MEAP]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile Middleware]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Sync]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=364</guid>
		<description><![CDATA[A Mobile Enterprise Application Platform (MEAP) allows corporate IT departments to support multiple mobile applications on a single platform. Gartner states that this market currently tops $1 billion, and forecasts that 95% of the world&#8217;s organizations will standardize on a &#8230; <a href="http://robtiffany.com/the-windows-phone-7-mobile-enterprise-application-platform-meap-tech-ed-europe-2010/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A Mobile Enterprise Application Platform (MEAP) allows corporate IT departments to support multiple mobile applications on a single platform. Gartner states that this market currently tops $1 billion, and forecasts that 95% of the world&#8217;s organizations will standardize on a single MEAP offering by 2012. Companies looking for a better ROI are moving to reusable platforms instead of building tactical, ad-hoc mobile solutions that support only a single app.</p>
<p>Attendees of this session will learn how to save money by steering away from point solutions and moving on to Microsoft&#8217;s MEAP stack. Come see what Microsoft&#8217;s Next-Gen Mobile Enterprise Application Platform looks like, and learn how it will support the cloud and a broader range of mobile platforms and operating systems, including Windows Phone 7.</p>
<div>Come check out session <strong>WPH212-LNC</strong> and I’ll see you next week in <strong>Berlin at <a href="http://europe.msteched.com/default.aspx" target="_blank">Tech Ed Europe 2010</a></strong>!</div>
<p>-Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/the-windows-phone-7-mobile-enterprise-application-platform-meap-tech-ed-europe-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Developing Cloud Connected Applications for Windows Phone 7 @ Tech Ed Europe 2010</title>
		<link>http://robtiffany.com/developing-cloud-connected-applications-for-windows-phone-7-tech-ed-europe-2010/</link>
		<comments>http://robtiffany.com/developing-cloud-connected-applications-for-windows-phone-7-tech-ed-europe-2010/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 17:42:20 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[Windows Azure]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://robtiffany.com/?p=357</guid>
		<description><![CDATA[The Silverlight development environment has proven itself to be a rich, capable and adaptable runtime that has reached across platforms to support Windows, the Mac, the Web, Nokia and Windows Phone 7.  Azure is Microsoft’s powerful cloud offering that brings compute, &#8230; <a href="http://robtiffany.com/developing-cloud-connected-applications-for-windows-phone-7-tech-ed-europe-2010/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>The Silverlight development environment has proven itself to be a rich, capable and adaptable runtime that has reached across platforms to support Windows, the Mac, the Web, Nokia and Windows Phone 7.  Azure is Microsoft’s powerful cloud offering that brings compute, database, storage, and web services to Windows Phone 7 devices.</div>
<p></p>
<div>To ensure the best experience for mobile users, apps built for Windows Phone 7 must implement an occasionally-connected pattern of development that might be unfamiliar to Silverlight developers for the other platforms.  In this session, learn how to build mobile apps that adjust their behavior based on changing network conditions.  Also learn how to conquer unreliable wireless networks by implementing RESTful principles to ensure your messages are both compact and fast.  Then take those WCF REST + JSON Azure services and use them to retrieve SQL Azure tables, rows and columns in order to drive the behavior of your mobile applications.  Finally, learn how to build an in-memory database that you can query with LINQ and save its data to Isolated Storage to ensure that your Windows Phone apps keep working regardless of network conditions.</div>
<p></p>
<div>Come check out session <strong>WPH304-IS</strong> and I’ll see you next week in <strong>Berlin at <a href="http://europe.msteched.com/default.aspx" target="_blank">Tech Ed Europe 2010</a></strong>!</div>
<div>
<p>-Rob</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/developing-cloud-connected-applications-for-windows-phone-7-tech-ed-europe-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows Phone 7 Line of Business App Dev :: Consuming an Azure WCF REST + JSON Service</title>
		<link>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-consuming-an-azure-wcf-rest-json-service/</link>
		<comments>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-consuming-an-azure-wcf-rest-json-service/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 03:40:25 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Debug]]></category>
		<category><![CDATA[Emulator]]></category>
		<category><![CDATA[Isolated Storage]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[ObservableCollection]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Singleton]]></category>
		<category><![CDATA[SQL Azure]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[Visual Studio 2010 Express for Windows Phone]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[WebClient]]></category>
		<category><![CDATA[Windows Azure]]></category>
		<category><![CDATA[Windows Server]]></category>
		<category><![CDATA[Wireless]]></category>

		<guid isPermaLink="false">http://robtiffany.com/windows-phone-7/windows-phone-7-line-of-business-app-dev-consuming-an-azure-wcf-rest-json-service</guid>
		<description><![CDATA[In my last two articles, I showed you how to build WCF REST services using Visual Studio 2010 that can reside on-premise in Windows Server 2008 or in the Cloud in Windows Azure.&#160; Furthermore, I demonstrated pulling data from a &#8230; <a href="http://robtiffany.com/windows-phone-7-line-of-business-app-dev-consuming-an-azure-wcf-rest-json-service/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In my last two articles, I showed you how to build <strong>WCF REST</strong> services using <strong>Visual Studio 2010</strong> that can reside <strong>on-premise</strong> in <strong>Windows Server 2008</strong> or in the <strong>Cloud</strong> in <strong>Windows Azure</strong>.&#160; Furthermore, I demonstrated pulling data from a table in <strong>SQL Server/SQL Azure</strong>.&#160; I <strong>serialized .NET Objects</strong> using lightweight <strong>JSON</strong> to speed data transfers over even the slowest wireless data networks.&#160; Now it’s time to call that <strong>REST</strong> service from <strong>Windows Phone 7</strong>.</p>
<p>Launch <strong>VS2010</strong> and open the solution you created to build the <strong>WCF Service Web Role</strong> in <strong>Azure</strong> last time.&#160; Right-click on the solution and add a <strong>Windows Phone Application project</strong>.&#160; Change the name to <strong>ContosoPhone</strong>.</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/10/WP71.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="WP71" border="0" alt="WP71" src="http://robtiffany.com/wp-content/uploads/2010/10/WP71_thumb.png" width="644" height="365" /></a></p>
<p>Part of the magic of making all this work is to have both the <strong>Azure Development Fabric</strong> and the <strong>Windows Phone 7 project</strong> start when it comes time to debug.&#160; Most developers are accustomed to only having a single startup project so let’s make sure you have everything we need running when you hit F5.&#160; Right-click on the solution and select Properties.&#160; Select <strong>Startup Project</strong> and then click on the<strong> Multiple startup projects</strong> radio button.&#160; Set both the <strong>AzureRestService</strong> and <strong>ContosoPhone</strong> projects <strong>Action</strong> value to <strong>Start</strong> and click OK as shown below:</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/10/WP72.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="WP72" border="0" alt="WP72" src="http://robtiffany.com/wp-content/uploads/2010/10/WP72_thumb.png" width="644" height="405" /></a></p>
<p>With the startup configuration complete, the next thing I want you to do is copy <strong>Customer.cs</strong> from the <strong>AzureRestService</strong> <strong>project</strong> to the new <strong>ContosoPhone</strong> <strong>project</strong> since you’ll need it to create local Customer objects when you retrieve the data from the WCF call.&#160; In this new <strong>Customer</strong> class you’ll need to change the <strong>Namespace</strong> to <strong>ContosoPhone</strong> and remove <strong>using System.Web;</strong> at the top of the class.&#160; In order to support the <strong>DataContract()</strong> and <strong>DataMember()</strong> attributes, you’ll need to add a reference to <strong>System.Runtime.Serialization</strong> in order to get it to compile.</p>
<p>Drag a Button on to your MainPage.xaml and call it Test.&#160; Double-click on this Button and add the following WebClient code to the click event:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; WebClient webClient = new WebClient();        <br />&#160;&#160;&#160; Uri uri = new Uri(&quot;</strong></font><a href="http://127.0.0.1:48632/service1.svc/getdata?number=8&quot;);"><font size="1"><strong>http://127.0.0.1:48632/service1.svc/getdata?number=8&quot;);</strong></font></a>    <br /><font size="1"><strong>&#160;&#160;&#160; webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompletedTest);       <br />&#160;&#160;&#160; webClient.OpenReadAsync(uri);        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>As you can see above, I create a <strong>WebClient</strong> and a <strong>Uri</strong> object that points to the local Url presented by the <strong>Azure Development Fabric</strong>.&#160; The port number my be different on your machine so double-check.&#160; This is the test <strong>REST</strong> service from the last article used to prove that you’re calls are making it through.&#160; You’ve made this call with your web browser and <strong>Windows Phone 7</strong> will call it the same way.&#160; Since all calls are <strong>asynchronous</strong> and the <strong>WebClient</strong> above created an event handler, copy the following code into the <strong>MainPage</strong> class and make sure to add <strong>using System.IO;</strong> at the top:</p>
<p><font size="1"><strong>void OpenReadCompletedTest(object sender, OpenReadCompletedEventArgs e)       <br />{        <br />&#160;&#160;&#160; try        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; StreamReader reader = new System.IO.StreamReader(e.Result);        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; MessageBox.Show(reader.ReadToEnd().ToString());        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; reader.Close();        <br />&#160;&#160;&#160; }        <br />&#160;&#160;&#160; catch (Exception ex)        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />&#160;&#160;&#160; }        <br />}</strong></font></p>
<p>In the event handler above, I use the <strong>StreamReader</strong> to grab the entire <strong>XML</strong> return value.&#160; The fact that I’m using <strong>WebClient</strong> means that <strong>callbacks</strong> are run on the <strong>UI thread</strong> thus relieving you of the need to use the dispatcher to update the UI.&#160; This allows you to display the following XML string in the MessageBox:</p>
<p><strong><font size="2">&lt;string xmlns=&quot;http://schemas.microsoft.com/2003/10/Serialization/&quot;&gt;You entered: 8&lt;/string&gt;</font></strong></p>
<p>It’s time to try this thing out so hit F5.&#160; If it compiles and everything executes properly, you should see both a <strong>web browser</strong> pointing to the root of your Azure services as well as your <strong>emulator</strong> and you can test your services with both.&#160; Click the simple<strong> Test Button</strong> on your <strong>Silverlight MainPage</strong> and the <strong>MessageBox</strong> should pop up after the XML result is returned from Azure displaying the answer:</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/10/WP73.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="WP73" border="0" alt="WP73" src="http://robtiffany.com/wp-content/uploads/2010/10/WP73_thumb.png" width="255" height="484" /></a></p>
<p>Click the Back button on the <strong>Emulator</strong> to close your app and close the web browser window to shut down Azure.&#160; </p>
<p>Now it’s time to do something a little more ambitious like return the <strong>JSON-encoded</strong> list of Customers from <strong>SQL Azure</strong>.&#160; Unlike most books and articles on <strong>Silverlight</strong> and <strong>RIA Services</strong> that you may have read, I’m not going to return this data and immediately <strong>data-bind</strong> it to a control.&#160; As a long-time <strong>mobile and wireless</strong> guy that understands <strong>intermittent connectivity</strong> and the importance of an <strong>offline data store</strong>, I’m going to have you put this data in a local database first.&#160; Since <strong>SQL Server Compact</strong> is nowhere to be found and I don’t want you going off and using a <strong>3rd party</strong> or <strong>open source embedded database</strong>, I’m going to show you how to create a simple one of your own.</p>
<p>Right-click on your <strong>ContosoPhone</strong> project and select <strong>Add</strong> | <strong>Class</strong>.&#160; Name this new class <strong>Database</strong>.&#160; </p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/10/WP74.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="WP74" border="0" alt="WP74" src="http://robtiffany.com/wp-content/uploads/2010/10/WP74_thumb.png" width="644" height="397" /></a></p>
<p>You’re going to turn this class into a <strong>Singleton</strong> to create an<strong> in-memory database</strong> which will ensure that only instance is available.&#160; For simplicity’s sake, just copy the code below into the new Database class:</p>
<p><font size="1"><strong>using System;       <br />using System.Net;        <br />using System.Windows;        <br />using System.Collections.Generic;        <br />using System.Collections.ObjectModel;</strong></font></p>
<p><font size="1"><strong>namespace ContosoPhone       <br />{        <br />&#160;&#160;&#160; sealed class Database        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Declare Instance        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; private static readonly Database instance = new Database();</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Private Constructor       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; private Database() { }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //The entry point into this Database       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public static Database Instance        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; get        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return instance;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Declare Private Variables       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; private ObservableCollection&lt;Customer&gt; customerTable = null;</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160;&#160;&#160;&#160;&#160; //Customer Table       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; public ObservableCollection&lt;Customer&gt; Customers        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; get { return customerTable; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; set { customerTable = value; }        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }        <br />&#160;&#160;&#160; }        <br />}</strong></font></p>
<p>As you can see above, I’ve had you create a <strong>sealed</strong> <strong>class</strong> with a <strong>private</strong>, <strong>static</strong>, <strong>readonly</strong> <strong>constructor</strong> as an entry point following a popular .NET method of implementing a <strong>Singleton</strong>.&#160; The big thing here is the <strong>Customers</strong> property of type <strong>ObservableCollection&lt;Customer&gt;</strong>.&#160; Since each Customer object is a <strong>Row</strong> with properties that are <strong>Columns</strong>, then it’s easy to think of this <strong>ObservableCollection</strong> of these <strong>Customer</strong> objects as a <strong>Table</strong>.&#160; You now have the beginnings of a simple, in-memory database with which to store all the Customer objects when they arrive from the <strong>Cloud</strong>.</p>
<p>Start out by dragging another button on to <strong>MainPage.xaml</strong> and calling it <strong>Get Customers</strong>.&#160; Double-click on this Button and add the following <strong>WebClient</strong> code to the click event:</p>
<p><font size="1"><strong>try       <br />{        <br />&#160;&#160;&#160; WebClient webClient = new WebClient();        <br />&#160;&#160;&#160; Uri uri = new Uri(&quot;</strong></font><a href="http://127.0.0.1:48632/service1.svc/customers&quot;);"><font size="1"><strong>http://127.0.0.1:48632/service1.svc/customers&quot;);</strong></font></a>    <br /><font size="1"><strong>&#160;&#160;&#160; webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompletedCustomers);       <br />&#160;&#160;&#160; webClient.OpenReadAsync(uri);        <br />}        <br />catch (Exception ex)        <br />{        <br />&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />}</strong></font></p>
<p>You’ll notice that it looks almost identical to the previous <strong>WebClient</strong> call except this time you’re just adding <strong>/customers</strong> to the end of <strong>service1.svc</strong>.&#160; The beauty of the <strong>UriTemplate</strong> is that Microsoft makes it just that easy to call a REST service from WCF.&#160; Since the above code created an event handler, paste this following code into the MainPage class to handle the callback:</p>
<p><font size="1"><strong>void OpenReadCompletedCustomers(object sender, OpenReadCompletedEventArgs e)       <br />{        <br />&#160;&#160;&#160; DataContractJsonSerializer ser = null;</strong></font></p>
<p><font size="1"><strong>&#160;&#160;&#160; try       <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; ser = new DataContractJsonSerializer(typeof(ObservableCollection&lt;Customer&gt;));        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; Database.Instance.Customers = ser.ReadObject(e.Result) as ObservableCollection&lt;Customer&gt;;        <br />&#160;&#160;&#160; }        <br />&#160;&#160;&#160; catch (Exception ex)        <br />&#160;&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; MessageBox.Show(ex.Message);        <br />&#160;&#160;&#160; }        <br />}</strong></font></p>
<p>You’ll immediately see a bunch of <strong>squiggly lines</strong> telling you something is missing.&#160; Add a <strong>reference</strong> to <strong>System.Servicemodel.Web</strong> and then add <strong>using</strong> <strong>System.Runtime.Serialization.Json;</strong> at the top in order to fix the problems with <strong>DataContractJsonSerializer</strong>.&#160; Next add <strong>using System.Collections.ObjectModel;</strong> at the top to fix the <strong>ObservableCollection</strong> squigglies.&#160; Give your solution a quick Rebuild to ensure that everything compiles.</p>
<p>In analyzing the new code I just had you add, you’ll notice the use of <strong>DataContractJsonSerializer</strong> which in this case is used to <strong>de-serialize JSON-encoded Customer objects</strong> that are downloading over the air.&#160; It does this by casting them as <strong>ObservableCollection&lt;Customer&gt;</strong> which works because I had you copy that class from the <strong>AzureRestService</strong> project.&#160; In a world of right-clicking to add a <strong>Service/Web Reference</strong> to consume <strong>SOAP</strong> web services, you never had to know what was going on under the covers to create an easy to use proxy.&#160; You also never saw Visual Studio create hidden classes that looked just like the ones found on the server side so your client would have something to work with and so that intellisense worked.&#160; </p>
<p>The last important line of code you see is setting the Customers table of your in-memory database equal to the de-serialization of the <strong>OpenReadCompletedEventArgs</strong>.&#160; I think we’re ready to try out this code.&#160; If all goes well, you’ll have a bunch of downloaded Customer data stored in an <strong>in-memory database</strong> on <strong>Windows Phone 7</strong>.</p>
<p>Set a <strong>breakpoint</strong> at the <strong>declaration</strong> of the <strong>DataContractJsonSerializer</strong>, hit <strong>F5</strong>, and click the <strong>Get Customers</strong> button!</p>
<p><a href="http://robtiffany.com/wp-content/uploads/2010/10/WP75.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="WP75" border="0" alt="WP75" src="http://robtiffany.com/wp-content/uploads/2010/10/WP75_thumb.png" width="644" height="365" /></a>    </p>
<p>Success looks like the picture above!&#160; I hovered my mouse over <strong>Database.Instance.Customers</strong> and revealed that I was now storing <strong>Customers</strong> with <strong>Cities</strong>, <strong>CustomerId’s</strong>, <strong>PostalCodes</strong>, <strong>RouteId’s</strong> and <strong>StateProvinces</strong> for all to see in<strong> Visual Studio’s</strong> amazing debugger.</p>
<p>You are now consuming <strong>wireless-friendly</strong> <strong>WCF REST + JSON Services</strong> from both <strong>Windows Server</strong> and <strong>Windows Azure</strong> with data coming from <strong>SQL Server/SQL Azure</strong>.&#160; Windows Phone 7 is connected to tiny, fast, efficient services designed to thrive in unreliable/slow wireless coverage.&#160; You now know how to serialize/de-serialize .NET objects as JSON and you’ve also created your own in-memory database.</p>
<p>So what’s next?&#160; In my next article, I’ll show you how to <strong>query</strong> this new in-memory database using <strong>LINQ</strong> and I’ll show you how to <strong>save the data</strong> in your local tables to <strong>Isolated Storage</strong> so you can keep using your apps even when the network has disappeared.    </p>
<p>Keep coding and I’ll see everyone at Tech Ed in Berlin!</p>
<p>-Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/windows-phone-7-line-of-business-app-dev-consuming-an-azure-wcf-rest-json-service/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Mobile Merge Replication Performance and Scalability Cheat Sheet</title>
		<link>http://robtiffany.com/mobile-merge-replication-performance-and-scalability-cheat-sheet/</link>
		<comments>http://robtiffany.com/mobile-merge-replication-performance-and-scalability-cheat-sheet/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 21:06:00 +0000</pubDate>
		<dc:creator>Rob Tiffany</dc:creator>
				<category><![CDATA[Sync]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Articles]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Distributor]]></category>
		<category><![CDATA[Enterprise Data Synchronization]]></category>
		<category><![CDATA[High Availability]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[Internet Information Services]]></category>
		<category><![CDATA[MEAP]]></category>
		<category><![CDATA[Merge Replication]]></category>
		<category><![CDATA[Mobile Enterprise Application Platform]]></category>
		<category><![CDATA[Mobile Middleware]]></category>
		<category><![CDATA[Publication]]></category>
		<category><![CDATA[Publisher]]></category>
		<category><![CDATA[SQL CE]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server Compact]]></category>
		<category><![CDATA[SSCE]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[Subscriber]]></category>
		<category><![CDATA[Synchronize]]></category>
		<category><![CDATA[Windows 7]]></category>
		<category><![CDATA[Windows Mobile]]></category>
		<category><![CDATA[Windows phone]]></category>
		<category><![CDATA[Windows Vista]]></category>
		<category><![CDATA[Windows XP]]></category>

		<guid isPermaLink="false">http://robtiffany.com/sql-server-compact/meap-mobile-merge-replication-performance-and-scalability-cheat-sheet</guid>
		<description><![CDATA[If your Mobile Enterprise Application Platform (MEAP) is using SQL Server Merge Replication to provide the mobile middleware and reliable wireless wire protocol for SQL Server Compact (SSCE) running on Windows Mobile 5/6.x devices + Windows XP/Vista/7 laptops, desktops and tablets; below is a guide to help you build the fastest, most scalable systems: <a href="http://robtiffany.com/mobile-merge-replication-performance-and-scalability-cheat-sheet/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If your Mobile Enterprise Application Platform (MEAP) is using SQL Server <em><strong>Merge Replication</strong></em> to provide the mobile middleware and reliable wireless wire protocol for SQL Server Compact (SSCE) running on Windows Mobile and Windows Embedded Handheld devices + Windows XP/Vista/7 tablets, laptops, desktops, slates, and netbooks; below is a guide to help you build the fastest, most scalable systems:</p>
<h2>Active Directory</h2>
<ul>
<li>Since your clients will be passing in their Domain\username + password credentials when they sync, both IIS and SQL Server will make auth requests of the Domain Controller. Ensure that you have at least a primary and backup Domain Controller, that the NTDS.dit disk drives are big enough to handle the creation of a large number of new AD DS objects (mobile users and groups), and that your servers have enough RAM to cache all those objects in memory.</li>
</ul>
<h2>Database Schema</h2>
<ul>
<li>Ensure your schema is sufficiently de-normalized so that you never have to perform more than a 4-way JOIN across tables. This affects server-side JOIN filters as well as SSCE performance.</li>
<li>To ensure uniqueness across all nodes participating in the sync infrastructure, use GUIDs for your primary keys so that SQL Server doesn’t have to deal with the overhead of managing Identity ranges. Make sure to mark your GUIDs as <strong>ROWGUIDCOL</strong> for that table so that Merge won’t try to add an additional <strong>Uniqueidentifier</strong> column to the table.  Don&#8217;t create clustered indexes when using GUIDs as primary keys because they will suffer horrible fragmentation that will rapidly degrade performance.  Just use a normal index.</li>
<li>Create clustered indexes for your primary keys when using Indentity columns, Datetime, or other natural keys.  Ensure that every column in every table that participates in a WHERE clause is indexed.</li>
</ul>
<h2>Distributor</h2>
<ul>
<li>If your network connection is fast and reliable like Wi-Fi or Ethernet, your SSCE client has more than 32 MB of free RAM, and SQL Server isn&#8217;t experiencing any deadlocks due to contention with ETL operations or too many concurrent Merge Agents, create a new Merge Agent Profile based on the <strong>High Volume Server-to-Server Profile</strong> so that SQL Server will perform more work per round-trip and speed up your synchronizations.</li>
<li>If you&#8217;re using a 2G/3G Wireless Wide Area Network connection, create a Merge Agent Profile based on the <strong>Default Profile</strong> so that SQL Server will perform less work and use fewer threads per round-trip during synchronization than the <strong>High Volume Server to Server Profile</strong> which will help to reduce server locking contention and perform less work per round trip which will make your synchronizations more likely to succeed.</li>
<li>In order to prevent SQL Server from performing Metadata Cleanup every time a Subscriber synchronizes, set the <strong>–MetadataRetentionCleanup</strong> parameter to <strong>0</strong>.</li>
<li>As SQL Server has to scale up to handle a higher number of concurrent users in the future, locking contention will increase due to more Merge Agents trying to perform work at the same time.  When this happens, adjust the parameters of the <strong>Default Profile</strong> so that both <strong> –SrcThreads</strong> and <strong>–DestThreads</strong> are equal to <strong>1</strong>.</li>
</ul>
<h2>Publication</h2>
<ul>
<li>When defining the Articles you’re going to sync, only check the minimum tables and columns needed by the Subscriber to successfully perform its work.</li>
<li>For Lookup/Reference tables that aren’t modified by the Subscriber, mark those as <strong>Download-only</strong> to prevent change-tracking metadata from being sent to the Subscriber.</li>
<li>Despite the fact the <strong>column-level</strong> tracking sends less data over the air, stick with <strong>row-level</strong> tracking so SQL Server won’t have to do as much work to track the changes.</li>
<li>Use the default conflict resolver where the “Server wins” unless you absolutely need a different manner of picking a winner during a conflict.</li>
<li>Use Static Filters to reduce the amount of server data going out to all Subscribers.</li>
<li>Make limited use of Parameterized Filters which are designed to reduce and further specify the subset of data going out to a particular Subscriber based on a HOST_NAME() which creates data partitions.  This powerful feature slows performance and reduces scalability with each additional filter, so it must be used sparingly.</li>
<li><em><strong>Keep filter queries simple</strong></em> and don’t use IN clauses, sub-selects or any kind of circular logic.</li>
<li>Strive to always create &#8220;well-partitioned&#8221; Articles where all changes that are uploaded/downloaded are mapped to only the single partition ID for best performance and scalability.
<ul>
<li>When using Parameterized Filters, always create non-overlapping data partitions where each row from a filtered table only goes to a single Subscriber instead of more than one which will avoid the use of certain Merge metadata tables.</li>
<li>Each Article in this scenario can only be pubished to a single Publication</li>
<li>A Subscriber cannot insert rows that do not belong to its partition ID.</li>
<li>A Subscriber cannot update columns that are involved in filtering.</li>
<li>In a join filter hierarchy, a regular article cannot be the parent of a &#8220;well-partitioned&#8221; article.</li>
<li>The join filter in which a well-partitioned article is the child must have the join_unique_key set to a value of 1 which relates to the <strong>Unique key</strong> check box of the Add Join dialog.  This means there&#8217;s a one-to-one or one-to-many relationship with the foreign key.</li>
<li>Each &#8220;well-partitioned&#8221; Article can have only one subset or join filter. The article can have a subset filter and be the parent of a join filter, but cannot have a subset filter and be the child of a join filter.</li>
</ul>
</li>
<li>Never extend a filter out to more than 4 joined tables.</li>
<li>Do not filter tables that are primarily lookup/reference tables, small tables, and tables with data that does not change.</li>
<li>Schedule the Snapshot Agent to run once per day to create an unfiltered schema Snapshot.</li>
<li>Set your Subscriptions to expire as soon as possible to keep the amount change-tracking metadata SQL Server has to manage to an absolute minimum. Normally, set the value to 2 to accommodate 3-day weekends since 24 hours are automatically added to the time to account for multiple time zones. If server-side change tracking isn’t needed and Subscribers are pulling down a new database every day and aren’t uploading data, then set the expiration value to 1.</li>
<li>Set <strong>Allow parameterized filters</strong> equal to True.</li>
<li>Set <strong>Validate Subscribers</strong> equal to HOST_NAME().</li>
<li>Set <strong>Precompute partitions</strong> equal to True to allow SQL Server to optimize synchronization by computing in advance which data rows belong in which partitions.</li>
<li>Set <strong>Optimize synchronization</strong> equal to False if <strong>Precompute partitions</strong> is equal to True.  Otherwise set it to True to optimize filtered Subscriptions by storing more metadata at the Publisher.</li>
<li>Set <strong>Limit concurrent processes</strong> equal to True.</li>
<li>Set <strong>Maximum concurrent processes</strong> equal to the number of SQL Server processor cores.  If exceesive locking contention occurs, reduce the number of concurrent processes until the problem is fixed.</li>
<li>Set <strong>Replicate schema changes</strong> equal to True.</li>
<li>Check <strong>Automatically define a partition and generate a snapshot if needed when a new Subscriber tries to synchronize</strong>. This will reduce Initialization times since SQL Server creates and applies snapshots using the fast BCP utility instead of a series of slower SELECT and INSERT statements.</li>
<li>Add data partitions based on unique HOST_NAMEs and schedule the Snapshot Agent to create those filtered Snapshots nightly or on the weekend so they’ll be built using the fast BCP utility and waiting for new Subscribers to download in the morning.</li>
<li>Ensure that SQL Server has 1 processor core and 2 GB of RAM for every 100 concurrent Subscribers utilizing bi-directional sync. Add 1 core and 2 GB of RAM server for every additional 100 concurrent Subscribers you want to add to the system.  Never add more Subscribers and/or IIS servers without also adding new cores and RAM to the Publisher.</li>
<li>Turn off <strong>Hyperthreading</strong> in the BIOS of the SQL Server as it has been known to degrade SQL Server performance.</li>
<li>Do not add your own user-defined triggers to tables on a Published database since Merge places 3 triggers on each table already.</li>
<li>Add one or more <strong>Filegroups</strong> to your database to contain multiple, secondary database files spread out across many physical disks.</li>
<li>Limit use of large object types such as text, ntext, image, varchar(max), nvarchar(max) or varbinary(max) as they require a significant memory allocation and will negatively impact performance.</li>
<li>Set SQL Servers’s minimum and maximum memory usage to within 2 GB of total system memory so it doesn’t have to allocate more memory on-demand.</li>
<li>Always use SQL Server 2008 R2 and Windows Server 2008 R2 since they work better together because they take advantage of the next generation networking stack which dramatically increases network throughput. They can also scale up as high as 256 cores.</li>
<li>Due to how Merge Replication tracks changes with triggers, Merge Agents, and tracking tables, it will create locking contention withDML/ ETL operations.  This contention degrades server performance which negatively impacts sync times with devices.  This contention should be mitgated by performing large INSERT/UPDATE/DELETE DML/ETL operations during a nightly maintenance window when Subscribers aren’t synchronizing.</li>
<li>Since Published databases result in slower DML/ETL operations, perform changes in bulk by using XML Stored Procedures to boost performance.</li>
<li>To improve the performance of pre-computed partitions when DML/ETL operations result in lots of data changes, ensure that changes to a Parent table in a join filter are made before corresponding changes in the child tables.  This means that when DML/ETL operations are pushing new data into SQL Server, they must add master data to the parent filter table first, and then add detail data to all the related child tables second, in order for that data to be pre-computed and optimized for sync.</li>
<li>Create filter partitions based on things that don’t change every day.  Partitions that are added and deleted from SQL Server and Subscribers that move from one partition to another is very disruptive to the performance of Merge Replication.</li>
<li>Always perform initializations and re-initializations over Wi-Fi or Ethernet when the device is docked because this is the slowest operation where the entire database must be downloaded instead of just deltas.  To determine rough estimates for initialization, multiply the size of the resulting SSCE .sdf file <strong>x</strong> the bandwidth speed available to the device.  A file copy over the expected network will also yield estimates for mininum sync times.  These times don&#8217;t include the work SQL Server and IIS must perform to provide the data or data INSERT times on SSCE.</li>
<li>If your SQL Server Publisher hits a saturation point with too many concurrent mobile Subscribers, you can scale it out creating a Server/Push Republishing hierarchy. Put the primary SQL Server Publisher at the top of the pyramid and have two or more SQL Servers subscribe to it. These can be unfiltered Subscriptions where all SQL Servers get the same data or the Subscribers can filter their data feeds by region for example. Then have the Subscribing SQL Servers Publish their Subscription for consumption by mobile SSCE clients.</li>
<li>Create just a single Publication.</li>
</ul>
<h2>Internet Information Services</h2>
<ul>
<li>Use the x64 version of the <strong>SQL Server Compact 3.5 SP2 Server Tools</strong> with Windows Server 2008 R2 running inside IIS 7.5.</li>
<li>Use a single Server Agent in a single Virtual Directory.</li>
<li>Ensure the IIS Virtual Directory where the Server Agent resides is on a fast solid-state drive that’s separate from the disk where Windows Server is installed to better support file I/O.</li>
<li>Use a low-end server with 2 processor cores and 2 GB of RAM to support 400 concurrent Subscribers queued at the same time.</li>
<li>Set the MAX<strong>_THREADS_PER_POOL </strong>Server Agent registry key equal to 2 to match the IIS processor cores and RAM. Do not set this value to a higher number than the number of cores.</li>
<li>Set the <strong>MAX_PENDING_REQUEST</strong> Server Agent registry key equal to 400 which means the Server Agent will queue up to 400 concurrent Subscribers waiting for one of the 2 worker threads to become available to sync with SQL Server.</li>
<li>Set the <strong>IIS Connection Limits</strong> property to 400 to prevent an unlimited number of connections reaching the Server Agent.</li>
<li>Add a new load-balanced IIS server for every additional 400 concurrent Subscribers you want to add to the system.</li>
</ul>
<h2>Subscriber</h2>
<ul>
<li>Use the appropriate x64, x86 or ARM version of SQL Server Compact 3.5 SP2 to take advantage of the <strong>PostSyncCleanup</strong> property of the <strong>SqlCeReplication</strong> object that can reduce the time it takes to perform an initial synchronization. Set the <strong>PostSyncCleanup</strong> property equal to 3 where neither <strong>UpdateStats</strong> nor <strong>CleanByRetention</strong> are performed.</li>
<li>Increase the <strong>Max Buffer Size</strong> connection string parameter to <strong>1024</strong> on a phone and <strong>4096</strong> on a PC to boost both replication and SQL query processing performance. If you have more RAM available, set those values even higher until you reach the law of diminishing returns.</li>
<li>Keep your SSCE database compact and fast by setting the <strong>Autoshrink Threshold</strong> connection string parameter to 10 so it starts reclaiming empty data pages once the database has become 10% fragmented.</li>
<li>Replication performance testing must be performed using actual PDAs to observe how available RAM, storage space and CPU speed affect moving data into the device’s memory area and how quickly this data is inserted into the SSCE database tables.  Since the SSCE database doubles in size during replication, the device must have enough storage available or the operation will fail.  Having plenty of available RAM is important so that SSCE can utilize its memory buffer to complete a Merge Replication operation more quickly.  With plenty of available RAM and storage, a fast CPU will make all operations faster.</li>
<li>The PDA must have at least an extra 32 MB of available free RAM that can be used by the .NET Compact Framework (NETCF) application.  If additional applications are running on the device at the same time, even more RAM is needed.  If a NETCF application has insufficient RAM is will discard its compiled code and run in interpreted mode which will slow the application down.  If the NETCF app is still under memory pressure after discarding compiled code, Windows Mobile will first tell the application to return free memory to the operating system and then will terminate the app if needed.</li>
<li>Set the <strong>CompressionLevel</strong> property of the <strong>SqlCeReplication </strong>object to 0 for fast connections and increment it from 1 to 6 on slower connections like GPRS to increase speed and reduce bandwidth consumption.</li>
<li>Tune the <strong>ConnectionRetryTimeout</strong>, <strong>ConnectTimeout</strong>, <strong>ReceiveTimeout</strong> and <strong>SendTimeout</strong> properties of the <strong>SqlCeReplication</strong> object based on expected bandwidth speeds:</li>
</ul>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="160"><strong>Property</strong></td>
<td valign="top" width="160"><strong>High Bandwidth</strong></td>
<td valign="top" width="160"><strong>Medium Bandwidth</strong></td>
<td valign="top" width="160"><strong>Low Bandwidth</strong></td>
</tr>
<tr>
<td valign="top" width="160">ConnectionRetryTimeout</td>
<td valign="top" width="160">30</td>
<td valign="top" width="160">60</td>
<td valign="top" width="160">120</td>
</tr>
<tr>
<td valign="top" width="160">ConnectTimeout</td>
<td valign="top" width="160">3000</td>
<td valign="top" width="160">6000</td>
<td valign="top" width="160">12000</td>
</tr>
<tr>
<td valign="top" width="160">ReceiveTimeout</td>
<td valign="top" width="160">1000</td>
<td valign="top" width="160">3000</td>
<td valign="top" width="160">6000</td>
</tr>
<tr>
<td valign="top" width="160">SendTimeout</td>
<td valign="top" width="160">1000</td>
<td valign="top" width="160">3000</td>
<td valign="top" width="160">6000</td>
</tr>
</tbody>
</table>
<ul>
<li>You can decrease potentially slow SSCE file I/O by adjusting the Flush Interval connection string parameter to write committed transactions to disk less often than the default of every 10 seconds.  Test longer intervals between flushes like 20 or 30 seconds. Keep in mind that these transactions can be lost if the disk or system fails before flushing occurs so be careful.</li>
<li>When replicating data that has been captured in the field by the device, perform Upload-only syncs to shorten the duration.</li>
</ul>
<h2>Storage</h2>
<ul>
<li>Use a Fibre Channel SAN with 15k RPM or solid-state disks for best I/O performance.</li>
<li>Databases should reside on a RAID 10, unshared LUN comprised of at least 6 disks.</li>
<li>Database logs should reside on a RAID 10, unshared LUN comprised of at least 6 disks.</li>
<li>Tempdb should reside on a RAID 10, unshared LUN comprised of at least 6 disks.</li>
<li>The Tempdb log should reside on a RAID 10, unshared LUN comprised of at least 6 disks.</li>
<li>The Snapshot share should reside on a RAID 10, unshared LUN comprised of at least 6 disks.  This disk array should be large enough to accommodate a growing number of filtered Snapshots. Snapshot folders for Subscribers that no longer use the system must be manually deleted.</li>
<li>Merge Replication metadata tables should reside on a RAID 10, unshared LUN comprised of at least 6 disks.</li>
<li>Increase your Host Bus Adapter (HBA) queue depths to 64.</li>
<li>Your Publication database should be broken up into half the number of files as the SQL Server has processor cores. Each file must be the same size.</li>
<li>Tempdb should be pre-sized with an auto-growth increment of 10%. It should be broken up into the same number of files as the SQL Server has processor cores. Each file must be the same size.</li>
</ul>
<h2>High Availability</h2>
<ul>
<li>Load-balance the IIS servers to scale them out. Enable Server Affinity (stickiness) since the <strong>Replication Session Control Blocks</strong> that transmit data between the Server Agent and SSCE are stateful. Test to ensure that your load-balancer is actually sending equal amounts of Subscriber sync traffic to each IIS server.  Some load-balancers can erroneously send all traffic to a single IIS server if not properly configured.</li>
<li>Implement Windows Clustering so that SQL Server can failover to a second node.</li>
<li>Using SQL Server Mirroring so that your Published database will failover to a standby server.</li>
<li>Make a second SQL Server into an unfiltered Subscriber to your Publisher so that it can take over Merge Replication duties for mobile clients as a Republisher if the primary SQL Server fails. SSCE clients would just have to reinitialize their Subscriptions to begin synchronizing with the new Republisher.</li>
</ul>
<h2>Ongoing Maintenance</h2>
<ul>
<li>Use the Replication Monitor to have a real-time view of the synchronization performance of all your Subscribers.</li>
<li>Use the web-based SQL Server Compact Server Agent Statistics and Diagnostics tools to monitor the health and activity of the Server Agent running on IIS.</li>
<li>Create a SQL Job to execute the <strong>sp_MSmakegeneration</strong> stored procedure after large DML operations. Regular execution after INSERTING/UPDATING/DELETING data from either DML/ETL operations or after receiving lots of changes from Subscribers will maintain subsequent sync performance. Executing this stored procedure from the server-side is preferable to having it executed as a result of a Subscriber sync which would block all other Subscribers.</li>
<li>During your nightly maintenance window, rebuild the indexes and update the statistics of the following Merge Replication metadata tables:
<ul>
<li><strong>MSmerge_contents</strong></li>
<li><strong>MSmerge_tombstone</strong></li>
<li><strong>MSmerge_genhistory</strong></li>
<li><strong>MSmerge_current_partition_mappings</strong></li>
<li><strong>MSmerge_past_partition_mappings</strong></li>
<li><strong>MSmerge_generation_partition_mappings</strong></li>
</ul>
</li>
<li>If you notice performance degradation during the day due to a large number of Subscribers making large changes to the database, you can updates the statistics (with fullscan) of the Merge Replication metadata tables more frequently throughout the day to force stored proc recompiles to get a better query plan.
<ul>
<li>UPDATE STATISTICS MSmerge_generation_partition_mappings WITH FULLSCAN</li>
<li>UPDATE STATISTICS MSmerge_genhistory WITH FULLSCAN</li>
</ul>
</li>
<li>Rebuild/defrag indexes on your database tables and Merge Replication metadata tables throughout the day to reduce locking contention and maintain performance.</li>
<li>Use the Missing Indexes feature of SQL Server to tell you which indexes you could add that would give your system a performance boost. Do not add recommended indexes to Merge system tables.</li>
<li>Use the Database Engine Tuning Advisor to give you comprehensive performance tuning recommendations that cover every aspect of SQL Server.</li>
<li>Monitor the performance of the following counters:
<ul>
<li><strong>Processor Object: % Processor Time: </strong>This counter represents the percentage of processor utilization. A value over 80% is a CPU bottleneck.</li>
<li><strong>System Object: Processor Queue Length: </strong>This counter represents the number of threads that are delayed in the processor Ready Queue and waiting to be scheduled for execution. A value over 2 is bottleneck and shows that there is more work available than the processor can handle. Remember to divide the value by the number of processor cores on your server.</li>
<li><strong>Memory Object: Available Mbytes: </strong>This counter represents the amount of physical memory available for allocation to a process or for system use. Values below 10% of total system RAM indicate that you need to add additional RAM to your server.</li>
<li><strong>PhysicalDisk Object: % Disk Time: </strong>This counter represents the percentage of time that the selected disk is busy responding to read or write requests. A value greater than 50% is an I/O bottleneck.</li>
<li><strong>PhysicalDisk Object: Average Disk Queue Length: </strong>This counter represents the average number of read/write requests that are queued on a given physical disk. If your disk queue length is greater than 2, you’ve got an I/O bottleneck with too many read/write operations waiting to be performed.</li>
<li><strong>PhysicalDisk Object: Average Disk Seconds/Read and Disk Seconds/Write: </strong>These counters represent the average time in seconds of a read or write of data to and from a disk. A value of less than 10 ms is what you’re shooting for in terms of best performance. You can get by with subpar values between 10 – 20 ms but anything above that is considered slow. Times above 50 ms represent a very serious I/O bottleneck.</li>
<li><strong>PhysicalDisk Object: Average Disk Reads/Second and Disk Writes/Second: </strong>These counters represent the rate of read and write operations against a given disk. You need to ensure that these values stay below 85% of a disk’s capacity by adding disks or reducing the load from SQL Server. Disk access times will increase exponentially when you get beyond 85% capacity.</li>
</ul>
</li>
<li>A limited number of database schema changes can be made and synchronized down to SSCE Subscribers without any code changes which makes it easier to update your system as it evolves over time.</li>
<li>Use a Merge Replication Test Harness to stress test the entire system.  The ability to simulate hundreds or thousands of concurrent synchronizing Subscribers allows you to monitor performance and the load on the system.  This is helpful in properly configuring and tuning SQL Server, IIS, and the Windows Mobile devices.  It will tell you where you’re having problems and it will let you predict how much server hardware you will need to support growing numbers of Subscribers over time.  It’s also very important to simulate worst-case scenarios that you never expect to happen.</li>
</ul>
<p>I hope this information sufficiently empowers you to take on the largest MEAP solutions that involve SQL Server Merge Replication and SQL Server Compact.  If you need a deeper dive, go check out my book on Enterprise Data Synchronization <a title="http://www.amazon.com/Enterprise-Synchronization-Microsoft-Compact-Replication/dp/0979891213/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1271964573&amp;sr=1-1" href="http://www.amazon.com/Enterprise-Synchronization-Microsoft-Compact-Replication/dp/0979891213/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1271964573&amp;sr=1-1">http://www.amazon.com/Enterprise-Synchronization-Microsoft-Compact-Replication/dp/0979891213/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1271964573&amp;sr=1-1</a> over at Amazon.  Now go build a fast and scalable solution for your company or your customers.</p>
<p>Best Regards,</p>
<p>Rob</p>
<p>P.S.  If your solution doesn&#8217;t require all the advanced features found in Merge Replication, I highly recommend you use Remote Data Access (RDA).  This is a much simpler sync technology that&#8217;s extremely fast, scalable, and easier to manage.</p>
]]></content:encoded>
			<wfw:commentRss>http://robtiffany.com/mobile-merge-replication-performance-and-scalability-cheat-sheet/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

