{"id":13499,"date":"2022-06-28T14:33:16","date_gmt":"2022-06-28T21:33:16","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=13499"},"modified":"2025-06-13T21:51:46","modified_gmt":"2025-06-14T04:51:46","slug":"asp-net-core-crud-nosql-part-4","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/","title":{"rendered":"ASP.NET Core CRUD with NoSQL: Part 4"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">ASP.NET CRUD apps include interaction with data that consists of create, read, update, and delete. In <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-with-nosql-part-1\/\"><span style=\"font-weight: 400;\">part 1<\/span><\/a><span style=\"font-weight: 400;\">, we setup a basic ASP.NET Core project. In <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/asp-net-crud-nosql-part-2\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">part 2<\/span><\/a><span style=\"font-weight: 400;\">, we added the first <\/span><i><span style=\"font-weight: 400;\">read<\/span><\/i><span style=\"font-weight: 400;\"> endpoint, using a SQL++ query against wishlist data. In <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-3\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">part 3<\/span><\/a><span style=\"font-weight: 400;\">, we added another read endpoint, this time using the key-value API.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Until this point, the only data modifications we\u2019ve made have been directly in the Couchbase Capella UI. In this post, let\u2019s add an endpoint to handle creating and updating wishlist data.<\/span><\/p>\n<h2><b>SQL++ vs Key-Value: Revisited<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">SQL++ includes <\/span><em><span style=\"font-weight: 400;\">INSERT<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">UPDATE<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">DELETE<\/span><\/em><span style=\"font-weight: 400;\"> syntax. So, we could use SQL++ to build an endpoint for mutating data. It would be very similar to the code written in <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/asp-net-crud-nosql-part-2\/\"><span style=\"font-weight: 400;\">part 2<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">One keyword in SQL++ that you might not have seen before is <\/span><em><span style=\"font-weight: 400;\">UPSERT<\/span><\/em><span style=\"font-weight: 400;\">. As you might guess, it\u2019s a combination of <\/span><em><span style=\"font-weight: 400;\">UPDATE<\/span><\/em><span style=\"font-weight: 400;\"> and <\/span><em><span style=\"font-weight: 400;\">INSERT<\/span><\/em><span style=\"font-weight: 400;\"><em>.<\/em> An update will happen if the data already exists; an insert will happen if it doesn\u2019t. Here\u2019s how an upsert endpoint using SQL++ might look:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:default decode:true\">[HttpPost]\r\n[Route(\"api\/editWithSql\")]\r\npublic async Task&lt;IActionResult&gt; CreateOrEditWithSql(WishlistItem item)\r\n{\r\n\u00a0 \u00a0 var bucket = await _bucketProvider.GetBucketAsync(\"demo\");\r\n\u00a0 \u00a0 var cluster = bucket.Cluster;\r\n\r\n\u00a0 \u00a0 var id = item.Id ?? Guid.NewGuid();\r\n\r\n\u00a0 \u00a0 var result = await cluster.QueryAsync&lt;WishlistItem&gt;(\r\n\u00a0 \u00a0 \u00a0 \u00a0 @\"UPSERT INTO demo._default.wishlist (KEY, VALUE)\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 VALUES ($id, { \"\"name\"\" : $name });\",\r\n\u00a0 \u00a0 \u00a0 \u00a0 options =&gt; options\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .Parameter(\"id\", id)\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .Parameter(\"name\", item.Name)\r\n\u00a0 \u00a0 );\r\n\r\n\u00a0 \u00a0 return Ok(result);\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Two important things to point out about this code:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">It handles both create and update. If <\/span><em><span style=\"font-weight: 400;\">item<\/span><\/em><span style=\"font-weight: 400;\"> has a null ID, this code assumes that a new wishlist item is being created.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Parameterization: just as in relational databases, SQL++ can be vulnerable to <\/span><a href=\"https:\/\/owasp.org\/www-community\/attacks\/SQL_Injection\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">SQL injection<\/span><\/a><span style=\"font-weight: 400;\">, so parameterization is highly recommended. Notice that SQL++ syntax uses <\/span><em><span style=\"font-weight: 400;\">$<\/span><\/em><span style=\"font-weight: 400;\"> to indicate named paramters (e.g. <\/span><em><span style=\"font-weight: 400;\">$id<\/span><\/em><span style=\"font-weight: 400;\"> and <\/span><em><span style=\"font-weight: 400;\">$name<\/span><\/em><span style=\"font-weight: 400;\">).<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">This endpoint will work. But as was the case in <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-3\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">part 3<\/span><\/a><span style=\"font-weight: 400;\">, we do not have to use SQL++ to interact with Couchbase. In fact, very similar criteria apply to making the decision when to use key-value and when to use SQL++:<\/span><\/p>\n<table>\n<tbody>\n<tr>\n<td><strong>Use case<\/strong><\/td>\n<td><strong>Key-value?<\/strong><\/td>\n<td><strong>Why or why not?<\/strong><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Create a new user with key &#8220;73892&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Yes<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Direct access<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Modify a user with key &#8220;73892&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Yes<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Direct access<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Modify just the email address of a user with key &#8220;73892&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Yes<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Even if the user document is large, Couchbase has a key-based <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/guides\/updating-data.html#updating-a-sub-document\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">sub-document API<\/span><\/a><span style=\"font-weight: 400;\">, which allows you to modify a portion of the document.<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Modify a group of users with keys &#8220;73892&#8221;, &#8220;47212&#8221;, and &#8220;90491&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Yes<\/span><\/td>\n<td><span style=\"font-weight: 400;\">This may require multiple key-value operations, but this still may be faster than using a <em>SQL <\/em><\/span><em><span style=\"font-weight: 400;\">SELECT \u2026\u200b WHERE \u2026\u200b IN<\/span><\/em><span style=\"font-weight: 400;\"> query.<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Modify all addresses to use &#8220;OH&#8221; instead of &#8220;Ohio&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">No<\/span><\/td>\n<td><span style=\"font-weight: 400;\">User\u2019s state is likely a &#8220;secondary&#8221; attribute, not a key (multiple users can be from Ohio). This is a good use case for a SQL++ <\/span><span style=\"font-weight: 400;\">UPDATE<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400;\">Because this endpoint only needs to add or change one single wishlist item, let\u2019s use the key-value API instead.<\/span><\/p>\n<h2><b>Write a CreateOrEdit CRUD endpoint<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Before we get to coding, it\u2019s wise to think about whether <em>CreateOrEdit<\/em> should be a single endpoint, or split into a <em>Create<\/em> endpoint and an <em>Edit<\/em> endpoint. For this very simple wishlist app, there is no validation, authentication, or other system-wide cross cutting concerns. However, in a production system, &#8220;adding&#8221; data and &#8220;updating&#8221; data may very well follow different business rules and require different permissions. In that case, you may want to break the operations into two endpoints.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For now, let\u2019s start with a single endpoint that uses an &#8220;upsert&#8221;:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:default decode:true \">[HttpPost]\r\n[Route(\"api\/edit\")]\r\npublic async Task&lt;IActionResult&gt; CreateOrEdit(WishlistItem item)\r\n{\r\n\u00a0 \u00a0 var bucket = await _bucketProvider.GetBucketAsync(\"demo\");\r\n\u00a0 \u00a0 var collection = await bucket.CollectionAsync(\"wishlist\");\r\n\r\n\u00a0 \u00a0 var id = item.Id ?? Guid.NewGuid();\r\n\r\n\u00a0 \u00a0 await collection.UpsertAsync(id.ToString(), new\r\n\u00a0 \u00a0 {\r\n\u00a0 \u00a0 \u00a0 \u00a0 Name = item.Name\r\n\u00a0 \u00a0 });\r\n\r\n\u00a0 \u00a0 return Ok(new { success = true});\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Much like the SQL++ endpoint, this endpoint looks at <\/span><em><span style=\"font-weight: 400;\">Id<\/span><\/em><span style=\"font-weight: 400;\"> to determine whether this is a &#8220;create&#8221; or an &#8220;update&#8221;.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The <\/span><em><span style=\"font-weight: 400;\">UpsertAsync<\/span><\/em><span style=\"font-weight: 400;\"> function will either:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Create a new document with <\/span><em><span style=\"font-weight: 400;\">id.ToString()<\/span><\/em><span style=\"font-weight: 400;\"> as the key<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Change an existing document with a key of <\/span><em><span style=\"font-weight: 400;\">id.ToString()<\/span><\/em><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">In either case, once this endpoint finishes executing, you will end up with a JSON document like <\/span><em><span style=\"font-weight: 400;\">{ &#8220;name&#8221; = &#8220;wishlist item name&#8221;}<\/span><\/em><span style=\"font-weight: 400;\"> and a GUID as a key (technically all keys in Couchbase are strings, but we know it\u2019s a GUID string).<\/span><\/p>\n<p><strong>Note:\u00a0<\/strong><span style=\"font-weight: 400;\">One subtle difference between the two APIs, is that the <\/span><em><span style=\"font-weight: 400;\">UPSERT<\/span><\/em><span style=\"font-weight: 400;\"> statement will only mutate the one field (<\/span><em><span style=\"font-weight: 400;\">name<\/span><\/em><span style=\"font-weight: 400;\">), while the key-value method <\/span><em><span style=\"font-weight: 400;\">UpsertAsync<\/span><\/em><span style=\"font-weight: 400;\"> will mutate the entire document (which is only <\/span><em><span style=\"font-weight: 400;\">name<\/span><\/em><span style=\"font-weight: 400;\"> for now).<\/span><\/p>\n<h2><b style=\"color: #343e47; font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 50px;\">ASP.NET CRUD in action<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Fire up your application from Visual Studio with CTRL+F5, and you should see some new endpoints show up in the OpenAPI \/ Swagger UI:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-13501\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/06\/swagger-ui-endpoints.png\" alt=\"ASP.NET endpoints showing in Swagger UI\" width=\"787\" height=\"515\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/swagger-ui-endpoints.png 787w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/swagger-ui-endpoints-300x196.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/swagger-ui-endpoints-768x503.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/swagger-ui-endpoints-20x13.png 20w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">From an API consumer\u2019s perspective, both <\/span><em><span style=\"font-weight: 400;\">\/api\/edit<\/span><\/em><span style=\"font-weight: 400;\"> and <\/span><em><span style=\"font-weight: 400;\">\/api\/editWithSql<\/span><\/em><span style=\"font-weight: 400;\"> endpoints will function the same. Try it once leaving the ID blank to create a new item, then try it again with a known ID (use <\/span><span style=\"font-weight: 400;\"><em>\/api\/getall<\/em><\/span><span style=\"font-weight: 400;\">\u00a0if you need to get an ID) and observe what happens and what changes.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For instance, I added a new item &#8220;Digital Photo Frame&#8221;, by leaving the ID blank (my .NET code generated &#8220;<em>1c3de2e7-70ea-4ee2-803b-425bbf6251cb<\/em>&#8221; for me), and I updated the item with ID of &#8220;<em>2dab198b-1836-4409-9bdf-17275a2b2462<\/em>&#8221; to have a name of &#8220;Skyline Chili 2XL T-Shirt&#8221;. Here are the results as seen in the Couchbase Capella UI:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-13502\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/06\/couchbase-capella-ui-asp.net-project.png\" alt=\"Couchbase Capella UI showing ASP.NET project documents\" width=\"872\" height=\"463\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/couchbase-capella-ui-asp.net-project.png 872w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/couchbase-capella-ui-asp.net-project-300x159.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/couchbase-capella-ui-asp.net-project-768x408.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/couchbase-capella-ui-asp.net-project-818x434.png 818w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/06\/couchbase-capella-ui-asp.net-project-20x11.png 20w\" sizes=\"auto, (max-width: 872px) 100vw, 872px\" \/><\/p>\n<h2><b>What\u2019s next?<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">The ASP.NET Core project is connected to Couchbase Capella, and it is now creating\/updating (&#8220;upserting&#8221;) data with key-value (recommended) or SQL++ (not recommended for this specific situation).<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In the next blog post, we\u2019ll round out CRUD with &#8220;D&#8221; for &#8220;delete&#8221;.&#8221;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In the meantime, you should:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><a href=\"https:\/\/cloud.couchbase.com\/sign-up\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Sign up for a Capella free-trial<\/span><\/a><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Check out the <\/span><a href=\"https:\/\/cloud.couchbase.com\/sign-up\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Couchbase Playground for .NET<\/span><\/a><span style=\"font-weight: 400;\"> examples that you can run right in the browser.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>ASP.NET CRUD apps include interaction with data that consists of create, read, update, and delete. In part 1, we setup a basic ASP.NET Core project. In part 2, we added the first read endpoint, using a SQL++ query against wishlist [&hellip;]<\/p>\n","protected":false},"author":71,"featured_media":12603,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,10126,10127,2225,1816,2201],"tags":[2821],"ppma_author":[8937],"class_list":["post-13499","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-asp-dotnet","category-c-sharp","category-cloud","category-couchbase-server","category-tools-sdks","tag-dbaas"],"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>ASP.NET Core CRUD with NoSQL: Part 4 - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"In this post we look at the U in CRUD that stands for UPDATE, and we build an ASP.NET Core CURD endpoint that uses UPSERT in a SQL++ query.\" \/>\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\/asp-net-core-crud-nosql-part-4\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ASP.NET Core CRUD with NoSQL: Part 4\" \/>\n<meta property=\"og:description\" content=\"In this post we look at the U in CRUD that stands for UPDATE, and we build an ASP.NET Core CURD endpoint that uses UPSERT in a SQL++ query.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-06-28T21:33:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T04:51:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/12\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1707\" \/>\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=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/\"},\"author\":{\"name\":\"Matthew Groves\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/3929663e372020321b0152dc4fa65a58\"},\"headline\":\"ASP.NET Core CRUD with NoSQL: Part 4\",\"datePublished\":\"2022-06-28T21:33:16+00:00\",\"dateModified\":\"2025-06-14T04:51:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/\"},\"wordCount\":870,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/12\\\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg\",\"keywords\":[\"dbaas\"],\"articleSection\":[\".NET\",\"ASP.NET\",\"C#\",\"Couchbase Capella\",\"Couchbase Server\",\"Tools &amp; SDKs\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/\",\"name\":\"ASP.NET Core CRUD with NoSQL: Part 4 - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/12\\\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg\",\"datePublished\":\"2022-06-28T21:33:16+00:00\",\"dateModified\":\"2025-06-14T04:51:46+00:00\",\"description\":\"In this post we look at the U in CRUD that stands for UPDATE, and we build an ASP.NET Core CURD endpoint that uses UPSERT in a SQL++ query.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/12\\\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2021\\\/12\\\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg\",\"width\":2560,\"height\":1707,\"caption\":\"Couchbase ASP.NET Core tutorial\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/asp-net-core-crud-nosql-part-4\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ASP.NET Core CRUD with NoSQL: Part 4\"}]},{\"@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":"ASP.NET Core CRUD with NoSQL: Part 4 - The Couchbase Blog","description":"In this post we look at the U in CRUD that stands for UPDATE, and we build an ASP.NET Core CURD endpoint that uses UPSERT in a SQL++ query.","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\/asp-net-core-crud-nosql-part-4\/","og_locale":"en_US","og_type":"article","og_title":"ASP.NET Core CRUD with NoSQL: Part 4","og_description":"In this post we look at the U in CRUD that stands for UPDATE, and we build an ASP.NET Core CURD endpoint that uses UPSERT in a SQL++ query.","og_url":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/","og_site_name":"The Couchbase Blog","article_published_time":"2022-06-28T21:33:16+00:00","article_modified_time":"2025-06-14T04:51:46+00:00","og_image":[{"width":2560,"height":1707,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/12\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg","type":"image\/jpeg"}],"author":"Matthew Groves","twitter_card":"summary_large_image","twitter_creator":"@mgroves","twitter_misc":{"Written by":"Matthew Groves","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/"},"author":{"name":"Matthew Groves","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58"},"headline":"ASP.NET Core CRUD with NoSQL: Part 4","datePublished":"2022-06-28T21:33:16+00:00","dateModified":"2025-06-14T04:51:46+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/"},"wordCount":870,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/12\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg","keywords":["dbaas"],"articleSection":[".NET","ASP.NET","C#","Couchbase Capella","Couchbase Server","Tools &amp; SDKs"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/","url":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/","name":"ASP.NET Core CRUD with NoSQL: Part 4 - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/12\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg","datePublished":"2022-06-28T21:33:16+00:00","dateModified":"2025-06-14T04:51:46+00:00","description":"In this post we look at the U in CRUD that stands for UPDATE, and we build an ASP.NET Core CURD endpoint that uses UPSERT in a SQL++ query.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/12\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/12\/hannah-wei-aso6SYJZGps-unsplash-scaled.jpg","width":2560,"height":1707,"caption":"Couchbase ASP.NET Core tutorial"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/asp-net-core-crud-nosql-part-4\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"ASP.NET Core CRUD with NoSQL: Part 4"}]},{"@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\/13499","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=13499"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/13499\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/12603"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=13499"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=13499"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=13499"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=13499"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}