{"id":2083,"date":"2008-05-20T12:45:49","date_gmt":"2008-05-20T12:45:49","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/odatateam\/2008\/05\/20\/merge-vs-replace-semantics-for-update-operations\/"},"modified":"2008-05-20T12:45:49","modified_gmt":"2008-05-20T12:45:49","slug":"merge-vs-replace-semantics-for-update-operations","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/merge-vs-replace-semantics-for-update-operations\/","title":{"rendered":"Merge vs. Replace Semantics for Update Operations"},"content":{"rendered":"<p>So far Astoria has used \u201cmerge\u201d semantics for update. That is, an \u201cupdate\u201d operation (an HTTP PUT request) replaces the values of the properties for the target entity that are specified in the input payload; this applies both to properties and links. If a property or link is not present in a PUT operation, it means \u201cleave it with its current value\u201d. To null-out a property or link it has to be present in the PUT body and has to have a null marker (null attribute for properties, null href for links). <\/p>\n<p>While supporting merge is important and will remain part of Astoria, there are scenarios where we need \u201creplace\u201d semantics. That is, an operation where the entity properties are entirely replaced by those in the request body, even if the request body is partial. In particular, the AtomPub protocol requires PUT to have replace semantics. <\/p>\n<p><b>Operation semantics<\/b> <\/p>\n<p>In a \u201creplace\u201d operation, each property in the target entity either takes the value specified in the payload (if any) or its default value. The meaning of \u201cdefault value\u201d for a \u201creplace\u201d operation is server implementation-specific. The Astoria server will likely use the CLR default values for each value type and null for references.  <\/p>\n<p>For operations on primitive values (e.g. PUT \/Customers(123)\/CompanyName), there is no practical difference between \u201cmerge\u201d and \u201creplace\u201d.  <\/p>\n<p>A \u201creplace\u201d operation, just like a \u201cmerge\u201d operation, cannot specify different values in the key properties. That is, keys remain non-updatable in \u201creplace\u201d. Similarly, a \u201creplace\u201d operation is subject to the same requirements from the ETags perspective as a \u201cmerge\u201d operation. <\/p>\n<p>About links inside entity payloads: \u201creplace\u201d operations replace the properties in entities themselves, not its links. If you include a link in a \u201cmerge\u201d or \u201creplace\u201d operation we\u2019ll wire it up, but if you don\u2019t it\u2019ll maintain the existing links. <\/p>\n<p>About directly-addressed links: links are currently atomic values (just the link itself), so there is no difference between replacing it and merging it when operating on link resources (e.g. \/$links\/\u2026). Astoria servers should support both operations but keep identical semantics. The rest of this discussion won\u2019t touch on links as stand-alone resources anymore.  <\/p>\n<p>Note that these operational semantics are the same regardless of the actual format (Atom, JSON, etc.) used to represent the resources being exchanged. <\/p>\n<p>Finally, this in general does not apply to service operations, as the meaning of service operations is service-defined. It\u2019s interesting to think about whether in the Astoria server library we introduce some mechanism to allow it to expose a MERGE-enabled URL, but that would still require the user-implementation to make sense of it.  <\/p>\n<p><b>HTTP interface<\/b> <\/p>\n<p>AtomPub specifically requires HTTP PUT to mean replace. So we adjusted the way Astoria interprets PUT to mean \u201creplace\u201d. <\/p>\n<p>In order to request a \u201cmerge\u201d operation we have two options: <\/p>\n<p>1. Introduce a new HTTP method, \u201cMERGE\u201d, and rely on verb tunneling (POST + a header) for the cases where custom methods are not allowed. There has been talk about a PATCH verb in multiple circles including the AtomPub community, but it seems to be going in a somewhat different direction. <\/p>\n<p>2. Introduce a new custom header, \u201cDataServices-Merge\u201d or something, that when set to \u201c1\u201d in a PUT request indicates that the server should merge the body with the server entity instead of replacing it. <\/p>\n<p>While we\u2019re not thrilled with the idea of introducing a new HTTP method, overloading PUT with an extra header seems to be very problematic. If anything else, a server that does not support \u201cmerge\u201d through headers would see PUT as a regular \u201creplace\u201d request and perform an operation that\u2019s not what the client expected. Also other things break. For example, if a server sees an actual MERGE request and cannot handle it then it can respond with 405 \u2013 method not supported. <\/p>\n<p>So we\u2019re leaning toward MERGE and tunneling (we already support tunneling for PUT\/DELETE in Astoria servers and clients). <\/p>\n<p>Responses to \u201cmerge\u201d and \u201creplace\u201d requests are identical. <\/p>\n<p><b>.NET client<\/b> <\/p>\n<p>Using \u201cmerge\u201d from the client has several advantages: <\/p>\n<p>1. The server does not know what a client considers a \u201cwhole\u201d entity. The client may be using entity types that contain a subset of the properties of the server-side version, either due to versioning mismatches or because the client is not interested in all of the properties.  <\/p>\n<p>2. The client is pretty much required to use \u201cmerge\u201d to make links work. Since an entity might have been brought down to the client without its related entities expanded, one or more links won\u2019t be present, and if we used replace we\u2019d lose information on the server. <\/p>\n<p>Based on the above, it would seem that the client should do \u201cmerge\u201d, which will effectively result in \u201creplacing the subset the client knows about\u201d because the client always sends all the fields. <\/p>\n<p>The problem now is servers that don\u2019t implement \u201cmerge\u201d operation.&nbsp; One option is to require \u201cmerge\u201d for the client to work, but that leaves too many interesting scenarios out. Since we already had a SaveChangesOptions enum that\u2019s used as an argument to SaveChanges\/BeginSaveChanges, we introduced SaveChangeOptions.UpdateAsReplace to indicate that you want the client to use PUT. <\/p>\n<p><b>AJAX client<\/b> <\/p>\n<p>The AJAX client\u2019s DataService.update method can be extended with a new argument \u201cUpdateAsReplace\u201d that enables use of replace when set to true. By default we would continue to do \u201cmerge\u201d (this requires tweaking the library because currently DataService.update generates a PUT request). <\/p>\n<p>If the new boolean adds one too many arguments for update(), alternatively we could add a knob to the DataService class, we still made this change.  <\/p>\n<p><b>Astoria runtime-data source interaction<\/b> <\/p>\n<p>The only change in the interaction between Astoria and the data source should be that for the resource being replaced the system will call IUpdatable.ReplaceResource instead of IUpdatable.GetResource. <\/p>\n<p>Pablo Castro<br>Software Architect<br>Microsoft Corporation <\/p>\n<p>This post is part of the transparent design exercise in the Astoria Team. To understand how it works and how your feedback will be used please look at <a href=\"https:\/\/blogs.msdn.com\/astoriateam\/archive\/2007\/07\/20\/transparency-in-the-design-process.aspx\">this post<\/a>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>So far Astoria has used \u201cmerge\u201d semantics for update. That is, an \u201cupdate\u201d operation (an HTTP PUT request) replaces the values of the properties for the target entity that are specified in the input payload; this applies both to properties and links. If a property or link is not present in a PUT operation, it [&hellip;]<\/p>\n","protected":false},"author":512,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[27],"class_list":["post-2083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata","tag-design-notes"],"acf":[],"blog_post_summary":"<p>So far Astoria has used \u201cmerge\u201d semantics for update. That is, an \u201cupdate\u201d operation (an HTTP PUT request) replaces the values of the properties for the target entity that are specified in the input payload; this applies both to properties and links. If a property or link is not present in a PUT operation, it [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/2083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/users\/512"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=2083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/2083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media\/3253"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media?parent=2083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=2083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=2083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}