{"id":2708,"date":"2017-03-07T09:51:19","date_gmt":"2017-03-07T17:51:19","guid":{"rendered":"http:\/\/www.couchbase.com\/blog\/?p=2708"},"modified":"2024-09-12T02:19:18","modified_gmt":"2024-09-12T09:19:18","slug":"moving-sql-server-couchbase-app-migration","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/","title":{"rendered":"Moving from SQL Server to Couchbase Part 3: App Migration"},"content":{"rendered":"<div id=\"header\">\n<h2>Moving from SQL Server to Couchbase Part 3: App Migration<\/h2>\n<\/div>\n<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>In this series of blog posts, I\u2019m going to lay out the considerations when moving to a document database when you have a relational background. Specifically, Microsoft SQL Server as compared to <a href=\"https:\/\/developer.couchbase.com\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Server<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In three parts, I\u2019m going to cover:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\">Data modeling<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/sql-server-couchbase-data-migration\/\">Data migration<\/a><\/li>\n<li>Applications using the data (this blog post)<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>The goal is to lay down some general guidelines that you can apply to your application planning and design.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>If you would like to follow along, I\u2019ve created an application that demonstrates Couchbase and SQL Server side-by-side. <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">Get the source code from GitHub<\/a>, and make sure to <a href=\"https:\/\/couchbase.com\/downloads?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">download a developer preview of Couchbase Server<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_migrate_vs_rewrite\">Migrate vs Rewrite<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If you\u2019re building a new web app, then Couchbase Server is a good choice to use as your <strong>system of record<\/strong>. Flexible data modeling, fast data access, ease of scaling all make it a good choice.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Couchbase Server can supplement SQL Server in your existing web application. It can be a session store or a cache store. You don\u2019t have to replace your RDMBS to benefit from Couchbase Server. You can use it as your <strong>system of engagment<\/strong>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>However, if you\u2019re considering making a document database your &#8220;system of record&#8221; for an existing app, then you need to plan what to do about that application (assuming you\u2019ve already come up with a data modeling and data migration plan as covered in the earlier parts of this blog series). There are really two options:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Replace your data\/service layer<\/strong>. If you\u2019ve built your app in a way that decouples it from the underlying persistence, that\u2019s going to benefit you tremendously when switching from SQL Server to Couchbase. If you are using an SOA, for instance, then you might not have to make very many changes to the web application.<\/li>\n<li><strong>Rebuild your application<\/strong>. If you don\u2019t have a decoupled architecture, then you\u2019ll likely have to bite the bullet and rewrite\/refactor large portions of your application. This can be a significant cost that you\u2019ll have to factor in when deciding whether or not to switch to a document database. I wish I could say it would be easier, that there was some magic potion you could use. But remember, even if the cost of a rebuild is too great, you can still use Couchbase Server in<br \/>\ntandem with SQL Server.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>The pieces of your stack that you might need to rebuild or replace include:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>ADO.NET<\/strong> &#8211; If you are using plain ADO.NET or a micro-OR\/M like Dapper, these can be replaced by the Couchbase .NET SDK.<\/li>\n<li><strong>OR\/M<\/strong> &#8211; Entity framework, NHibernate, Linq2SQL, etc. These can be replaced by Linq2Couchbase<\/li>\n<li><strong>Any code that uses those directly<\/strong> &#8211; Any code that touches ADO.NET, OR\/Ms, or other SQL Server code will need to be replaced to use Couchbase (and\/or rewritten to introduce another layer of abstraction).<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>The rest of this blog post will be tips and guidelines that apply for rewriting, refactoring, or starting a new project.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_what_s_going_to_be_covered\">What\u2019s going to be covered<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Document databases force business logic out of the database to a larger extent than relational databases. As nice as it would be if Couchbase Server had every feature under the sun, there are always tradeoffs.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In this blog post, we will cover the changes to application coding that come with using Couchbase. At a high level, here is what will be covered in this blog post. On the left, a SQL Server feature; on the right, the closest equivalent when using Couchbase Server.<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<colgroup>\n<col style=\"width: 50%\" \/>\n<col style=\"width: 50%\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">SQL Server<\/th>\n<th class=\"tableblock halign-left valign-top\">Couchbase Server<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">tSQL<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">N1QL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Stored Procedures<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Service tier<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Triggers<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Service tier<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Views<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Map\/Reduce Views<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Autonumber<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Counter<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">OR\/M (Object\/relational mapper)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">ODM (Object data model)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">ACID<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Single-document ACID<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>In addition, we\u2019ll also be covering these important topics:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Serialization<\/li>\n<li>Security<\/li>\n<li>Concurrency<\/li>\n<li>SSIS, SSRS, SSAS<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_using_n1ql\">Using N1QL<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The <a href=\"https:\/\/www.couchbase.com\/n1ql\/\">N1QL (pronounced &#8220;nickel&#8221;)<\/a> query language is one of my favorite features of Couchbase Server. You are already comfortable with the SQL query language. With N1QL, you can apply your expertise to a document database.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Here are a few examples to show the <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/n1ql\/n1ql-intro\/n1ql-sql-differences.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">similarities between N1QL and tSQL<\/a>:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<colgroup>\n<col style=\"width: 50%\" \/>\n<col style=\"width: 50%\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">tSQL<\/th>\n<th class=\"tableblock halign-left valign-top\">N1QL<\/th>\n<\/tr>\n<\/thead>\n<tfoot>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">DELETE FROM [table] WHERE val1 = &#8216;foo&#8217;<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">DELETE FROM `bucket` WHERE val1 = &#8216;foo&#8217;<\/p>\n<\/td>\n<\/tr>\n<\/tfoot>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">SELECT * FROM [table]<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">SELECT * from `bucket`<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">SELECT t1.* , t2.* FROM [table1] t1 JOIN [table2] t2 ON t1.id = t2.id<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">SELECT b1.* , b2.* FROM `bucket` b1 JOIN `bucket` b2 ON KEYS b1.mykeys<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">INSERT INTO [table] (key, col1, col2) VALUES (1, &#8216;val1&#8242;,&#8217;val2&#8217;)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">INSERT INTO `bucket` (KEY, VALUE) VALUES (&#8216;1&#8217;, {&#8220;col1&#8243;:&#8221;val1&#8221;, &#8220;col2&#8243;:&#8221;val2&#8221;})<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">UPDATE [table] SET val1 = &#8216;newvalue&#8217; WHERE val1 = &#8216;foo&#8217;<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">UPDATE `bucket` SET val1 =&#8217;newvalue&#8217; WHERE val1 = &#8216;foo&#8217;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>Thanks to <a href=\"https:\/\/www.couchbase.com\/n1ql\/\">N1QL<\/a>, migrating your SQL queries should be less difficult than other document databases. Your data model will be different, and not every function in tSQL is (yet) available in N1QL. But for the most part, your existing tSQL-writing expertise can be applied.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Back to the shopping cart, here\u2019s an example of a simple tSQL query that would get shopping cart information for a given user:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\">SELECT c.Id, c.DateCreated, c.[User], i.Price, i.Quantity\r\nFROM ShoppingCart c\r\nINNER JOIN ShoppingCartItems i ON i.ShoppingCartID = c.Id\r\nWHERE c.[User] = 'mschuster'<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>In Couchbase, a shopping cart could be modeled as a single document, so a roughly equivalent query would be:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\">SELECT META(c).id, c.dateCreated, c.items, c.`user`\r\nFROM `sqltocb` c\r\nWHERE c.type = 'ShoppingCart'\r\nAND c.`user` = 'mschuster';<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Notice that while N1QL has <code>JOIN<\/code> functionality, no <code>JOIN<\/code> is necessary in this shopping cart query. All the shopping cart data is in a single document, instead of being spread out amongst multiple tables and rows.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The results aren\u2019t <em>exactly<\/em> the same: the N1QL query returns a more hierarchical result. But the query <em>could<\/em> be modified with an <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/n1ql\/n1ql-language-reference\/from.html#concept_rnt_zfk_np__unnest\"><code>UNNEST<\/code><\/a> to flatten out the results if necessary. <code>UNNEST<\/code> is an <em>intra-document join<\/em>, which is a feature that\u2019s necessary when writing SQL for JSON.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In many document databases other than Couchbase, you would likely have to learn an API for creating queries, and you would not be able to apply your tSQL experience to help ramp up. I\u2019m not saying that translation is always going to be a walk in the park, but it\u2019s going to be relatively easy compared to the alternatives. If you\u2019re starting a <strong>new<\/strong> project, then you\u2019ll be happy to know that your SQL-writing skills will continue to be put to good use!<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>When writing C# to interact with N1QL, there are a couple key concepts that are important to know.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><strong>Scan Consistency<\/strong>. When executing a N1QL query, there are several scan consistency options. Scan consistency defines how your N1QL query should behave towards indexing. The default behavior is &#8220;Not Bounded&#8221;, and it provides the best performance. At the other end of the spectrum is &#8220;RequestPlus&#8221;, and it provides the best consistency. There is also &#8220;AtPlus&#8221;, which is a good middle-ground, but takes a little more work. I <a href=\"https:\/\/www.couchbase.com\/blog\/new-to-couchbase-4.5-atplus\/\">blogged about Scan Consistency<\/a> back in June, and it\u2019s worth reviewing before you start writing N1QL in .NET.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><strong>Parameterization<\/strong>. If you are creating N1QL queries, it\u2019s important to <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.5\/sdk\/dotnet\/n1ql-queries-with-sdk.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">use parameterization<\/a> to avoid SQL injection. There are two options with N1QL: positional (numbered) parameters and named parameters.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Here\u2019s an example of both Scan Consistency and Parameterization used in C#:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">var query = QueryRequest.Create(n1ql);\r\nquery.ScanConsistency(ScanConsistency.RequestPlus);\r\nquery.AddNamedParameter(\"userId\", id);\r\nvar result = _bucket.Query&lt;Update&gt;(query);<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>I\u2019m not going to dive into the <a href=\"https:\/\/docs.couchbase.com\/server\/6.0\/n1ql\/n1ql-language-reference\/index.html\">N1QL query language<\/a> any more than this, because it is such a deep topic. But you can <a href=\"https:\/\/www.couchbase.com\/products\/n1ql\/\">check out the basics of N1QL<\/a> and <a href=\"https:\/\/query.pub.couchbase.com\/tutorial\/#1\">get started with the interactive N1QL tutorial<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_sql_stored_procedures\">SQL Stored Procedures<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>There is no equivalent of stored procedures (sprocs) in Couchbase. If you don\u2019t already have a service tier, and you are using sprocs to share some logic across domains, I recommend that you create a service tier and move the logic there.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In fact, I wasn\u2019t sure whether sprocs belonged in part 2 or part 3 of this blog series. Typical tiers in an enterprise application:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Web tier (UI &#8211; Angular\/React\/Traditional ASP.NET MVC)<\/li>\n<li>Service tier (ASP.NET WebApi)<\/li>\n<li>Database<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Sprocs live in the database, but they contain logic. The service tier also contains business logic. So do they count as data or functionality?<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>I took a Twitter straw poll to decide.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><span class=\"image\"><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/02\/047_01_twitter_sproc_poll.png\" alt=\"Twitter straw poll on Stored Procedures\" \/><\/span><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>But my recommendation is that if you already have a service tier, move the sproc logic into that. If you don\u2019t have a service tier, create one. This will live between the database and the UI.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In the source code for this series, I\u2019ve created a single stored procedure.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\">CREATE PROCEDURE SP_SEARCH_SHOPPING_CART_BY_NAME\r\n\t@searchString NVARCHAR(50)\r\nAS\r\nBEGIN\r\n\tSELECT c.Id, c.[User], c.DateCreated\r\n\tFROM ShoppingCart c\r\n\tWHERE c.[User] LIKE '%' + @searchString + '%'\r\nEND\r\nGO<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>This sproc can be executed from Entity Framework as follows:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public List&lt;ShoppingCart&gt; SearchForCartsByUserName(string searchString)\r\n{\r\n    var cmd = _context.Database.Connection.CreateCommand();\r\n    cmd.CommandText = \"SP_SEARCH_SHOPPING_CART_BY_NAME @searchString\";\r\n    cmd.Parameters.Add(new SqlParameter(\"@searchString\", searchString));\r\n    _context.Database.Connection.Open();\r\n    var reader = cmd.ExecuteReader();\r\n\r\n    var carts = ((IObjectContextAdapter) _context)\r\n        .ObjectContext\r\n        .Translate&lt;ShoppingCart&gt;(reader, \"ShoppingCarts\", MergeOption.AppendOnly);\r\n\r\n    var result = carts.ToList();\r\n    _context.Database.Connection.Close();\r\n    return result;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><em>By the way, that Entity Framework sproc code is ugly. Maybe I did it wrong? I\u2019m not trying to slander EF, but generally, I haven\u2019t used OR\/Ms and sprocs together much in my career. Certainly a piece of ADO.NET or Dapper code would be shorter and cleaner.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>This is a very simple sproc, but it introduces a basic search functionality. The benefits to such a sproc:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Reuse:<\/strong> The same sproc can be reused between different applications<\/li>\n<li><strong>Abstraction:<\/strong> The sproc implementation can be changed or improved. In this case, a basic <code>LIKE<\/code> could be switched out for a more robust full text search.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Any approach taken with introducing a service tier should provide the same benefits. I created an ASP.NET WebApi endpoint to take the place of the sproc.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">[HttpGet]\r\n[Route(\"api\/searchByName\/{searchString}\")]\r\npublic IHttpActionResult SearchByName(string searchString)\r\n{\r\n    var n1ql = @\"SELECT META(c).id, c.`user`\r\n        FROM `sqltocb` c\r\n        WHERE c.type = 'ShoppingCart'\r\n        AND c.`user` LIKE $searchString\";\r\n    var query = QueryRequest.Create(n1ql);\r\n    query.AddNamedParameter(\"searchString\", \"%\" + searchString + \"%\");\r\n    query.ScanConsistency(ScanConsistency.RequestPlus);\r\n    var results = _bucket.Query&lt;ShoppingCart&gt;(query).Rows;\r\n\r\n    return Json(results);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Note: for the sake of simplicity in the sample code, this endpoint actually lives in the same web project, but in production, it should be moved to its own project and deployed separately.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>This endpoint holds a N1QL query that is similar in nature to the above sproc. Let\u2019s see if it holds up to the same benefits:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Reuse?<\/strong> Yes. This endpoint can be deployed to its own server and be reused from other applications.<\/li>\n<li><strong>Abstraction?<\/strong> Again, yes. The implementation uses the naive <code>LIKE<\/code> approach, which we could improve by switching it to use <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/sdk\/dotnet\/full-text-searching-with-sdk.html\">Couchbase\u2019s Full Text Search features<\/a> without changing the API.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Instead of calling a sproc through Entity Framework, this endpoint would be called via HTTP. Here\u2019s an example that uses the RestSharp library:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public List&lt;ShoppingCart&gt; SearchForCartsByUserName(string searchString)\r\n{\r\n    \/\/ typically there would be authentication\/authorization with a REST call like this\r\n    var client = new RestClient(_baseUrl);\r\n    var request = new RestRequest(\"\/api\/searchByName\/\" + searchString);\r\n    request.AddHeader(\"Accept\", \"application\/json\");\r\n    var response = client.Execute&lt;List&lt;ShoppingCart&gt;&gt;(request);\r\n    return response.Data;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>If you are building a new project, I recommend that you create a service tier with the expectation of it being used across your enterprise. This allows you to have the same &#8220;shared code&#8221; that sprocs would normally provide without putting that code into the database.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>This is also true for SQL Server <strong>functions, user defined types, rules, user-defined CLR objects<\/strong>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Note: the above sproc example is a <code>SELECT<\/code> just to keep the example simple. In this case, you could potentially create a MapReduce View instead (which is discussed below). A MapReduce view cannot mutate documents though, so a service tier approach is a better general solution to replacing sprocs.<\/em><\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_sql_triggers\">SQL Triggers<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If sprocs weren\u2019t already controversial enough, just bring up triggers in a conversation. As with stored procedures, I generally recommend that you move the trigger logic into the service tier, away from the database. If your software project depends on a lot of triggers, or complex triggers, or a lot of complex triggers, then you might want to wait for another project to try using Couchbase Server in.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>That being said, there is some cutting-edge stuff that is being worked on that might be roughly equivalent to triggers. If you are interested in this, please contact me, and also stay tuned to <a href=\"https:\/\/www.couchbase.com\/blog\/\">the Couchbase Blog<\/a> for the latest information.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_views\">Views<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>In SQL Server, Views are a way to store complex queries on the server, as well as provide some performance benefits. In Couchbase, Map\/reduce views have been providing similar functionality for some time. For the most part, the functionality provided by views can be provided in a more expressive way with N1QL. However, views are not going away, and there are sometimes benefits to using them.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Map\/reduce views can be defined and stored on the Couchbase cluster. To create them, you define a &#8220;map&#8221; function (with JavaScript) and optionally a &#8220;reduce&#8221; function (also in JavaScript).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In the Couchbase Console UI, go to Indexes \u2192 Views \u2192 Create View. Create a design document, and create a view within that design document.<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\"><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/02\/047_01_Couchbase_View_editor.png\" alt=\"Editing a Map\/Reduce view in Couchbase\" \/><\/div>\n<div class=\"title\">Figure 1. Screenshot of the Map\/Reduce view editor in the latest Couchbase Console<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>At the center is the Map\/Reduce code that you are working on. A sample document and its meta-data is also shown to give you some visual help, and at the bottom you have some options for executing your view.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>For complete details on how views work, check out the <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/sdk\/dotnet\/view-queries-with-sdk.html\">MapReduce Views documentation<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>As a quick example, I want to create a view that lists only the people who have an age greater than 21.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">function (doc, meta) {\r\n  if(doc.age &gt; 21) {\r\n  \temit(meta.id, doc.name);\r\n  }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>This view would emit the key of the document and the value of the &#8220;name&#8221; field. If my bucket contained the following documents:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">foo1\t{\"age\":17,\"name\":\"Carmella Albert\"}\r\nfoo2\t{\"age\":25,\"name\":\"Lara Salinas\"}\r\nfoo3\t{\"age\":35,\"name\":\"Teresa Johns\"}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Then the results of the view would look like:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<colgroup>\n<col style=\"width: 50%\" \/>\n<col style=\"width: 50%\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Key<\/th>\n<th class=\"tableblock halign-left valign-top\">Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">&#8220;foo2&#8221;<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">&#8220;Lara Salinas&#8221;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">&#8220;foo3&#8221;<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">&#8220;Teresa Johns&#8221;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>The results of these views are updated automatically on an interval, and are also updated incrementally as documents are mutated. This means that, by default, the results of the views are <strong>eventually<\/strong> consistent with the actual documents. As a developer, you can <a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/architecture-overview.html\">specify the level of consistency<\/a> (or staleness) you want. This will have an impact on performance.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Map\/reduce views can be very helpful when you have very complex logic that\u2019s easier to write in JavaScript than it is to write in N1QL. There can also be performance benefits when you are working with a write-heavy system.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Views can be accessed from .NET using <code>ViewQuery<\/code>.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">var query = new ViewQuery().From(\"viewdesigndocument\", \"viewname\").Limit(10);\r\nvar people = bucket.Query&lt;dynamic&gt;(query);\r\nforeach (var person in people.Rows)\r\n    Console.WriteLine(landmark.Key);<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Alternatively, you could create N1QL queries instead of using Views. In many cases, N1QL will be easier to write, and the performance difference will be negligible. Unlike Views, the N1QL queries would live in the service tier. There is currently no way to store a &#8220;N1QL View&#8221; on the Couchbase Server cluster.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_serialization_deserialization\">Serialization\/deserialization<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Whether you\u2019re using N1QL, Views, or key\/value operations, it\u2019s important to consider how JSON is serialized and deserialized.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The .NET SDK uses <a href=\"https:\/\/www.newtonsoft.com\/json\">Newtonson JSON.NET<\/a>. If you are familiar with that tool (and who among .NET developers isn\u2019t), then remember that you can use the same attributes (like <a href=\"https:\/\/www.newtonsoft.com\/json\/help\/html\/SerializationAttributes.htm\">JsonProperty, JsonConverter<\/a>, etc). In some edge cases, it might be useful to create your own custom serializer, which is possible with the Couchbase .NET SDK. Check out the <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/sdk\/nonjson.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">documentation on serialization and non-JSON documents<\/a> for more information.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_security\">Security<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Couchbase has <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/security\/concepts-rba.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">role-based access control (RBAC)<\/a> for administrators.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Couchbase can integrate with LDAP to manage Couchbase administrators and assign roles to users. Couchbase can also create read-only users internally.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>There are some more robust changes and improvements coming to the Couchbase RBAC system, so stay tuned. In fact, I would recommend that you start <a href=\"https:\/\/www.couchbase.com\/blog\/introducing-developer-builds\/\">checking out the monthly developer builds<\/a>, as I expect to see some interesting improvements and features in this area soon!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_concurrency\">Concurrency<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Concurrency is something that you often have to deal with, especially in a web application. Multiple users could be taking actions that result in the same document being changed at the same time.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>SQL Server uses <a href=\"https:\/\/www.couchbase.com\/blog\/optimistic-or-pessimistic-locking-which-one-should-you-pick\/\">pessimistic locking<\/a> by default. This means that SQL Server expects rows to be in contention, and so it acts defensively. This is a sensible default for relational databases because denormalized data is spread across multiple tables and multiple rows. SQL Server does have the ability to use <a href=\"https:\/\/www.couchbase.com\/blog\/optimistic-or-pessimistic-locking-which-one-should-you-pick\/\">optimistic locking<\/a> as well, through a variety of <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ms173763.aspx\">transaction levels<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Couchbase also offers two options to deal with concurrency: optimistic and pessimistic.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><strong>Optimisitic<\/strong>. This is called &#8220;optimistic&#8221; because it works best when it\u2019s unlikely that a document will be in contention very often. You are making an optimistic assumption. On Couchbase, this is done with <a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/concurrent-document-mutations.html\">CAS (Compare And Swap)<\/a>. When you retrieve a document, it comes with meta data, including a CAS value (which is just a number). When you go to update that document, you can supply the CAS value. If the values match, then your optimism paid off, and the changes are saved. If they don\u2019t match, then the operation fails, and you\u2019ll have to handle it (a merge, an error message, etc). <em>If you don\u2019t supply a CAS value, then the changes will be saved no matter what.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><strong>Pessimistic<\/strong>. This is called &#8220;pessimistic&#8221; because it works best when you know a document is going to be mutated a lot. You are making a pessimistic assumption, and are forcibly locking the document. If you use <code>GetAndLock<\/code> in the .NET SDK, the document will be locked, which means it can\u2019t be modified. Documents are locked for a maximum of 15 seconds. You can set a lower value. You can also explicitly unlock a document, but you must keep track of the CAS value to do so.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>For more detail, check out the documentation on <a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/concurrent-mutations-cluster.html\">Concurrent Document Mutations<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_autonumber\">Autonumber<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Couchbase Server does not currently offer any sort of automatic key generation or sequential key numbering.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>However, you can <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/sdk\/core-operations.html\">use the <strong>Counter<\/strong> feature<\/a> to do something similar. The idea is that a document is set aside as a special counter document. This document can be incremented as an atomic operation, and the number can be used as a partial or whole key of the new document being created.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Ratnopam Chakrabarti, a developer for Ericsson, recently wrote a <a href=\"https:\/\/www.couchbase.com\/blog\/using-autonumber-in-couchbase\/\">guest blog post about how to create sequentially numbered keys with Couchbase Server<\/a>. His example is in Java, but it easy enough to follow, so I won\u2019t repeat his example here.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_or_ms_and_odms\">OR\/Ms and ODMs<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If you are using SQL Server, you might be familiar with OR\/Ms (Object-relational mappers). Entity Framework, NHibernate, Linq2SQL, and many others are OR\/Ms. OR\/Ms attempt to bridge the gap between structured data in C# and normalized data in relational databases. They also typically provide other capabilities like Linq providers, unit of work, etc. I believe that OR\/Ms follow the 80\/20 rule. They can be very helpful 80% of the time, and a pain in the neck the other 20%.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>For document databases, there is a much lower impedence mismatch, since C# objects can be serialized\/deserialized to JSON, and don\u2019t have to be broken up into a normalized set of tables.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>However, the other functionality that OR\/Ms provide can still be helpful in document databases. The equivalent tool is called an ODM (Object Document Model). These tools help you define a set of classes to map to documents. Ottoman and Linq2Couchbase are popular ODMs for Couchbase, for Node and .NET respectively.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><a href=\"https:\/\/github.com\/couchbaselabs\/Linq2Couchbase\">Linq2Couchbase<\/a> has a Linq provider. It\u2019s not an officially supported project (yet), but it is one of the most complete Linq providers I\u2019ve ever used, and is used in production by Couchbase customers.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Below is an example from the Linq2Couchbase documentation that should look somewhat familiar for users of Entity Framework and NHibernate.Linq:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">var context = new BucketContext(ClusterHelper.GetBucket(\"travel-sample\"));\r\nvar query = (from a in context.Query&lt;AirLine&gt;()\r\n             where a.Country == \"United Kingdom\"\r\n             select a).\r\n             Take(10);<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>I also used Linq2Couchbase in the sample code for this blog series. Here\u2019s an example for Shopping Carts:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">var query = from c in _context.Query&lt;ShoppingCart&gt;()\r\n    where c.Type == \"ShoppingCart\"  \/\/ could use DocumentFilter attribute instead of this Where\r\n    orderby c.DateCreated descending\r\n    select new {Cart = c, Id = N1QlFunctions.Meta(c).Id};\r\nvar results = query.ScanConsistency(ScanConsistency.RequestPlus)\r\n    .Take(10)\r\n    .ToList();<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Beyond being a great Linq provider, Linq2Couchbase also has an experimental change tracking feature. It\u2019s definitely worth checking out. Brant Burnett is one of the key contributers to the project, and he\u2019s also a <a href=\"https:\/\/developer.couchbase.com\/experts-and-champions?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Expert<\/a>. He presented a session at Couchbase Connect 2016 called <a href=\"https:\/\/www.youtube.com\/watch?v=X__mC2FArp4\">LINQing to data: Easing the transition from SQL<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>[youtube https:\/\/www.youtube.com\/watch?v=X__mC2FArp4&amp;w=560&amp;h=315]<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_transactions\">Transactions<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>I\u2019ve already covered pessimistic and optimistic locking for transactions on a single document. Because of those, we can say that Couchbase supports ACID transactions on a per-document level. Couchbase does not, at this time, support ACID transactions among multiple documents.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Thinking back to the <a href=\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\">first blog post on data modeling<\/a>, the need for multi-document transactions is often reduced or eliminated, compared to a relational model. A concept (like shopping cart) may require rows in multiple tables in a relational model, but a single document model in Couchbase.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>If you are following a referential model, as in the social media example from the <a href=\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\">first blog post<\/a>, you might be concerned about the lack of transactions. This highlights the importance of thinking about your use cases while creating your data model. If transactions are vital to your use case, the data model can often be structured to accomodate. <a href=\"https:\/\/www.couchbase.com\/forums\/\">We are happy to help you through this, just ask!<\/a><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Multi-document transaction support may come in the future if enough Couchbase developers and customers ask for it or need it. So, if you go through the exercise of designing a document database data model, and transactions are <em>still<\/em> a vital part of your project, then Couchbase may not be the best &#8220;system of record&#8221; for at least part of your project. Couchbase may still be the best &#8220;system of engagement&#8221;, able to help with scaling, caching, performance, and flexibility where needed.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><em>As a side note, it may be worth checking out the <a href=\"https:\/\/ndescribe.atlassian.net\/wiki\/display\/DOC\/Transactional+Documents\">NDescribe project<\/a>, as it includes an SDK that works on top of the Couchbase SDK and provides a transaction system. (Note that this is not an officially supported tool).<\/em><\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_ssis_ssas_ssrs\">SSIS, SSAS, SSRS<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Not everyone uses SQL Server Integration Services (SSIS), SQL Server Analysis Services (SSAS), and SQL Server Reporting Services (SSRS), but these are powerful features that SQL Server has for integration, reporting, and analysis.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>I can\u2019t give you a blanket &#8220;use X instead of Y&#8221; for these, because it depends very much on your use case. I can point you in the direction of some of the tools available for Couchbase that revolve around data processing, data transformation, reporting, and analysis.<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Kafka<\/strong> is an open source data streaming tool. Some of the <a href=\"https:\/\/kafka.apache.org\/uses\">popular use cases for Kafka<\/a> include messaging, website activity tracking, metrics, and more.<\/li>\n<li><strong>Spark<\/strong> is a data procesessing engine, intended for large-scale data processing and ETL.<\/li>\n<li><strong>Hadoop<\/strong> is a big data framework for distributed storage and processing.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p><a href=\"https:\/\/www.couchbase.com\/bigdata\/\">Couchbase has connectors<\/a> that support each of these three popular tools.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Finally, <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.5\/analytics\/introduction.html\"><strong>Couchbase Analytics<\/strong> is currently in developer preview<\/a>. It is intended as a data management engine that runs parallel to Couchbase Server. It\u2019s a developer preview, and is not yet recommended to be used in production, but you can <a href=\"https:\/\/www.couchbase.com\/downloads\/\">download Couchbase Analytics and Kafka, Spark, Hadoop extensions (click the Extensions tab) and try them out<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_summary\">Summary<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>We\u2019ve covered data modeling, data migration, and application migration through the lens of SQL Server. This is a good starting point for your next project, and will give you something to think about if you are considering migrating.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The <a href=\"https:\/\/developer.couchbase.com\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Developer Portal<\/a> contains more details and information about every aspect of Couchbase Server.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>I want to hear from you about what Couchbase can do to make your transition easier, whether you\u2019re migrating or starting fresh. Did I miss something? Do you have a tool or system that you recommend? Have questions? Check out the <a href=\"https:\/\/www.couchbase.com\/forums\/\">Couchbase Forums<\/a>, email me at <a href=\"mailto:matthew.groves@couchbase.com\">matthew.groves@couchbase.com<\/a> or find me on <a href=\"https:\/\/twitter.com\/mgroves\">Twitter @mgroves<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Moving from SQL Server to Couchbase Part 3: App Migration In this series of blog posts, I\u2019m going to lay out the considerations when moving to a document database when you have a relational background. Specifically, Microsoft SQL Server as [&hellip;]<\/p>\n","protected":false},"author":71,"featured_media":2574,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,1814,1816,1819,1812],"tags":[1806,1556],"ppma_author":[8937],"class_list":["post-2708","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-application-design","category-couchbase-server","category-data-modeling","category-n1ql-query","tag-entity-framework","tag-sql-server"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Moving from SQL Server to Couchbase Part 3: App Migration<\/title>\n<meta name=\"description\" content=\"In this blog post series, I&#039;m laying out the considerations when moving from Microsoft SQL Server to Couchbase Server. This post is about app migration.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Moving from SQL Server to Couchbase Part 3: App Migration\" \/>\n<meta property=\"og:description\" content=\"In this blog post series, I&#039;m laying out the considerations when moving from Microsoft SQL Server to Couchbase Server. This post is about app migration.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-03-07T17:51:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-12T09:19:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2048\" \/>\n\t<meta property=\"og:image:height\" content=\"949\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matthew Groves\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mgroves\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matthew Groves\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/\"},\"author\":{\"name\":\"Matthew Groves\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/3929663e372020321b0152dc4fa65a58\"},\"headline\":\"Moving from SQL Server to Couchbase Part 3: App Migration\",\"datePublished\":\"2017-03-07T17:51:19+00:00\",\"dateModified\":\"2024-09-12T09:19:18+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/\"},\"wordCount\":3837,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2017\\\/02\\\/geese-migration.jpg\",\"keywords\":[\"Entity Framework\",\"SQL Server\"],\"articleSection\":[\".NET\",\"Application Design\",\"Couchbase Server\",\"Data Modeling\",\"SQL++ \\\/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/\",\"name\":\"Moving from SQL Server to Couchbase Part 3: App Migration\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2017\\\/02\\\/geese-migration.jpg\",\"datePublished\":\"2017-03-07T17:51:19+00:00\",\"dateModified\":\"2024-09-12T09:19:18+00:00\",\"description\":\"In this blog post series, I'm laying out the considerations when moving from Microsoft SQL Server to Couchbase Server. This post is about app migration.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2017\\\/02\\\/geese-migration.jpg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2017\\\/02\\\/geese-migration.jpg\",\"width\":2048,\"height\":949,\"caption\":\"Geese migration licensed through Creative Commons https:\\\/\\\/commons.wikimedia.org\\\/wiki\\\/File:BrantaLeucopsisMigration.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/moving-sql-server-couchbase-app-migration\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Moving from SQL Server to Couchbase Part 3: App Migration\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/3929663e372020321b0152dc4fa65a58\",\"name\":\"Matthew Groves\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=gba51e6aacc53995c323a634e4502ef54\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g\",\"caption\":\"Matthew Groves\"},\"description\":\"Matthew D. Groves is a guy who loves to code. It doesn't matter if it's C#, jQuery, or PHP: he'll submit pull requests for anything. He has been coding professionally ever since he wrote a QuickBASIC point-of-sale app for his parent's pizza shop back in the 90s. He currently works as a Senior Product Marketing Manager for Couchbase. His free time is spent with his family, watching the Reds, and getting involved in the developer community. He is the author of AOP in .NET, Pro Microservices in .NET, a Pluralsight author, and a Microsoft MVP.\",\"sameAs\":[\"https:\\\/\\\/crosscuttingconcerns.com\",\"https:\\\/\\\/x.com\\\/mgroves\"],\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/author\\\/matthew-groves\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Moving from SQL Server to Couchbase Part 3: App Migration","description":"In this blog post series, I'm laying out the considerations when moving from Microsoft SQL Server to Couchbase Server. This post is about app migration.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/","og_locale":"en_US","og_type":"article","og_title":"Moving from SQL Server to Couchbase Part 3: App Migration","og_description":"In this blog post series, I'm laying out the considerations when moving from Microsoft SQL Server to Couchbase Server. This post is about app migration.","og_url":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/","og_site_name":"The Couchbase Blog","article_published_time":"2017-03-07T17:51:19+00:00","article_modified_time":"2024-09-12T09:19:18+00:00","og_image":[{"width":2048,"height":949,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","type":"image\/jpeg"}],"author":"Matthew Groves","twitter_card":"summary_large_image","twitter_creator":"@mgroves","twitter_misc":{"Written by":"Matthew Groves","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/"},"author":{"name":"Matthew Groves","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58"},"headline":"Moving from SQL Server to Couchbase Part 3: App Migration","datePublished":"2017-03-07T17:51:19+00:00","dateModified":"2024-09-12T09:19:18+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/"},"wordCount":3837,"commentCount":2,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","keywords":["Entity Framework","SQL Server"],"articleSection":[".NET","Application Design","Couchbase Server","Data Modeling","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/","url":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/","name":"Moving from SQL Server to Couchbase Part 3: App Migration","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","datePublished":"2017-03-07T17:51:19+00:00","dateModified":"2024-09-12T09:19:18+00:00","description":"In this blog post series, I'm laying out the considerations when moving from Microsoft SQL Server to Couchbase Server. This post is about app migration.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","width":2048,"height":949,"caption":"Geese migration licensed through Creative Commons https:\/\/commons.wikimedia.org\/wiki\/File:BrantaLeucopsisMigration.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Moving from SQL Server to Couchbase Part 3: App Migration"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58","name":"Matthew Groves","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=gba51e6aacc53995c323a634e4502ef54","url":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","caption":"Matthew Groves"},"description":"Matthew D. Groves is a guy who loves to code. It doesn't matter if it's C#, jQuery, or PHP: he'll submit pull requests for anything. He has been coding professionally ever since he wrote a QuickBASIC point-of-sale app for his parent's pizza shop back in the 90s. He currently works as a Senior Product Marketing Manager for Couchbase. His free time is spent with his family, watching the Reds, and getting involved in the developer community. He is the author of AOP in .NET, Pro Microservices in .NET, a Pluralsight author, and a Microsoft MVP.","sameAs":["https:\/\/crosscuttingconcerns.com","https:\/\/x.com\/mgroves"],"url":"https:\/\/www.couchbase.com\/blog\/author\/matthew-groves\/"}]}},"acf":[],"authors":[{"term_id":8937,"user_id":71,"is_guest":0,"slug":"matthew-groves","display_name":"Matthew Groves","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2708","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=2708"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2708\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/2574"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=2708"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=2708"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=2708"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2708"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}