{"id":1804,"date":"2014-12-16T18:04:10","date_gmt":"2014-12-16T18:04:10","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1804"},"modified":"2023-06-28T01:20:48","modified_gmt":"2023-06-28T08:20:48","slug":"tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/ko\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/","title":{"rendered":"TapMap \ud30c\ud2b8 1: Couchbase Server 2.0 \ubc0f .NET \ud074\ub77c\uc774\uc5b8\ud2b8 \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud558\uc5ec T \ub9ac\ud3ec\uc9c0\ud1a0\ub9ac \uc791\uc5c5\ud558\uae30"},"content":{"rendered":"<p>I\u2019ve been meaning to put together a reference application for using .NET and Couchbase Server.\u00a0 While traveling to London for the Progressive NoSQL conference at <a href=\"https:\/\/skillsmatter.com\/event\/nosql\/progressive-nosql-tutorials\/\">Skills Matter<\/a>, I passed the hours waiting for my hotel room to be ready by writing some code at a Startbucks for an application I call TapMap.<\/p>\n<p>The app is pretty straightforward; it\u2019s really just a Twitter knockoff with a particular focus on beers.\u00a0 The basic idea is that someone at a bar will report having found (and probably drunk) a particular brew at a particular place.\u00a0 That report is called a \u201ctap.\u201d\u00a0 The \u201cmap\u201d feature renders a series of taps on a Nokia Map, using GeoCouch.\u00a0 The value is that users can quickly learn where to find their favorite brews!<\/p>\n<p><img decoding=\"async\" style=\"width: 683px;height: 600px\" src=\"https:\/\/www.couchbase.com\/blog\/sites\/default\/files\/uploads\/all\/images\/tapmap_0.PNG\" alt=\"\" \/><\/p>\n<p>The code is still very alpha and my HTML skills need to be upgraded.\u00a0 But I\u2019ve implemented enough that I am going to start a series of posts on the code patterns and solutions exposed by TapMap.\u00a0 This post will be part one and will describe how to create a simple Repository of T for Couchbase using the .NET Client Library.\u00a0 You can get the code at <a href=\"https:\/\/github.com\/couchbaselabs\/TapMap\">https:\/\/github.com\/couchbaselabs\/TapMap<\/a>.<\/p>\n<p>If you\u2019re not familiar with repositories, the basic idea is that you have a class that is responsible for the data access of a domain object.\u00a0 So to query for a user by his or her email address, you would use the GetByEmail(string email) method of the UserRepository.\u00a0 Repositories also typically contain standard standard CRUD methods.\u00a0 There\u2019s a bit more to the pattern, but I\u2019ll demonstrate its basic usage.\u00a0 Read more at <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ff649690.aspx\">https:\/\/msdn.microsoft.com\/en-us\/library\/ff649690.aspx<\/a>.<\/p>\n<p>Inheritance is a natural way to achieve code reuse.\u00a0 TapMap uses a base repository class to provide CRUD methods to its subclasses.\u00a0 Additionally, the base class makes use of generics so that CRUD methods may return instances of T instead of just objects.\u00a0 Constraining T to a particular type also allows for some additional benefits that I\u2019ll discuss shortly.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">public<\/span> abstract <span style=\"color: #6666cc;font-weight: bold\">class<\/span> RepositoryBase<span style=\"color: #008000\">&lt;<\/span>T<span style=\"color: #008000\">&gt;<\/span> <span style=\"color: #0600ff;font-weight: bold\">where<\/span> T <span style=\"color: #008000\">:<\/span> ModelBase<br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #008080;font-style: italic\">\/\/crud methods here<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>As you may already know, Couchbase Server 2.0 does not impose a schema on its documents.\u00a0 You store a JSON document with any properties you wish to include.\u00a0 That said, all documents are stored with a reserved \u201c_id\u201d property that derives its value from its key.<\/p>\n<p>Adding a document as follows:<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Store<\/span><span style=\"color: #008000\">(<\/span>StoreMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Add<\/span>, <span style=\"color: #666666\">&#8220;beer_Three_Philosophers&#8221;<\/span>, <span style=\"color: #666666\">&#8220;{ <span style=\"color: #008080;font-weight: bold\">&#8220;<\/span>Name<span style=\"color: #008080;font-weight: bold\">&#8220;<\/span> : <span style=\"color: #008080;font-weight: bold\">&#8220;<\/span>Three Philosophers<span style=\"color: #008080;font-weight: bold\">&#8220;<\/span> }&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><\/div>\n<\/div>\n<p>Results in a document like the following:<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #666666\">&#8220;_id&#8221;<\/span> <span style=\"color: #008000\">:<\/span> <span style=\"color: #666666\">&#8220;beer_Three_Philosophers&#8221;<\/span>,<br \/>\n<span style=\"color: #666666\">&#8220;name&#8221;<\/span> <span style=\"color: #008000\">:<\/span> <span style=\"color: #666666\">&#8220;Three Philosophers&#8221;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>So to ensure that all of or model objects have this ID property we\u2019ll create a model base class that defines one.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #008000\">[<\/span>Serializable<span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> abstract <span style=\"color: #6666cc;font-weight: bold\">class<\/span> ModelBase<br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #008000\">[<\/span>JsonProperty<span style=\"color: #008000\">(<\/span>PropertyName <span style=\"color: #008000\">=<\/span> <span style=\"color: #666666\">&#8220;_id&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> Id <span style=\"color: #008000\">{<\/span> get<span style=\"color: #008000\">;<\/span> set<span style=\"color: #008000\">;<\/span> <span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>I won\u2019t dig into he JsonProperty pieces here.\u00a0 I\u2019m using Json.NET for serialization and wrote more about it at <a href=\"https:\/\/www.couchbase.com\/develop\/net\/next\/\">https:\/\/www.couchbase.com\/develop\/net\/next<\/a>.\u00a0 The important thing to note is that we have model objects with an \u201cId\u201d property and by constraining our repositories to use subclasses of ModelBase, we know we\u2019ll always have this property.<\/p>\n<p>When creating views, it\u2019s useful to have a taxonomy on documents so that it\u2019s easy to find all \u201cbeer\u201d documents or all \u201cuser\u201d documents or even to find a \u201cuser\u201d document with a given email address.\u00a0 To facilitate this requirement, we\u2019ll impose a \u201ctype\u201d property on all model documents.\u00a0 To our ModelBase, we\u2019ll add a readonly, abstract Type property.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #008000\">[<\/span>JsonProperty<span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;type&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> abstract <span style=\"color: #6666cc;font-weight: bold\">string<\/span> Type <span style=\"color: #008000\">{<\/span> get<span style=\"color: #008000\">;<\/span> <span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>Now that we understand the assumptions we can make of our model, let\u2019s return to our RespositoryBase class.<\/p>\n<p>The first thing our RepositoryBase class needs to do is define an instance of the CouchbaseCliet.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">\n<p><span style=\"color: #0600ff;font-weight: bold\">protected<\/span> <span style=\"color: #0600ff;font-weight: bold\">static<\/span> <span style=\"color: #0600ff;font-weight: bold\">readonly<\/span> CouchbaseClient _Client <span style=\"color: #008000\">=<\/span> <span style=\"color: #0600ff;font-weight: bold\">null<\/span><span style=\"color: #008000\">;<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">static<\/span> RepositoryBase<span style=\"color: #008000\">(<\/span><span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n_Client <span style=\"color: #008000\">=<\/span> <a href=\"https:\/\/www.google.com\/search?q=new+msdn.microsoft.com\"><span style=\"color: #008000\">new<\/span><\/a> CouchbaseClient<span style=\"color: #008000\">(<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<\/div>\n<\/div>\n<p>Since client setup is expensive, we\u2019re going to ensure it happens only once per AppDomain by creating a readonly static instance that\u2019s instantiated in a static constructor.\u00a0 The client is exposed as a protected field to subclasses who need to extend the basic CRUD methods in our base class.\u00a0 Note that this client depends on the Web.config having defined the \u201ccouchbase\u201d section.\u00a0 At some point, I\u2019ll add a IoC friendly version of our RepositoryBase.<\/p>\n<p>The repository base defines Create, Update and Save methods.\u00a0 These methods in turn call the private \u201cstore\u201d method with the appropriate StoreMode value.\u00a0 Create and Update are straightforward.\u00a0 Save simply creates a document when the key doesn\u2019t exist and replaces it when it does.\u00a0 The return values are the CAS value for the operation.\u00a0 At some point, I\u2019ll add CAS as an optional parameter. \u00a0The store method also calls a CasJson extension method that serializes all objects to JSON strings before saving them to Couchbase.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">\n<p><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">virtual<\/span> <span style=\"color: #6666cc;font-weight: bold\">ulong<\/span> Create<span style=\"color: #008000\">(<\/span>T model<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> store<span style=\"color: #008000\">(<\/span>StoreMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Add<\/span>, model<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">virtual<\/span> <span style=\"color: #6666cc;font-weight: bold\">ulong<\/span> Update<span style=\"color: #008000\">(<\/span>T model<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> store<span style=\"color: #008000\">(<\/span>StoreMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Replace<\/span>, model<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">virtual<\/span> <span style=\"color: #6666cc;font-weight: bold\">ulong<\/span> Save<span style=\"color: #008000\">(<\/span>T model<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> store<span style=\"color: #008000\">(<\/span>StoreMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Set<\/span>, model<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">private<\/span> <span style=\"color: #6666cc;font-weight: bold\">ulong<\/span> store<span style=\"color: #008000\">(<\/span>StoreMode mode, T model<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\nvar result <span style=\"color: #008000\">=<\/span> _Client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">CasJson<\/span><span style=\"color: #008000\">(<\/span>mode, BuildKey<span style=\"color: #008000\">(<\/span>model<span style=\"color: #008000\">)<\/span>, model<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> result<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Result<\/span> <span style=\"color: #008000\">?<\/span> result<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Cas<\/span> <span style=\"color: #008000\">:<\/span> <span style=\"color: #ff0000\">0<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<\/div>\n<\/div>\n<p>The private store method also makes use of the protected BuildKey method to create keys by a convention.\u00a0 Specifically, keys are composed from the Type property of the model and its Id property, with spaces replaced by underscores.\u00a0 TapMap isn\u2019t actually making use of this version of BuildKey as it\u2019s overridden in subclasses that use Create, Update or Save.\u00a0 I\u2019m considering adding a \u201cName\u201d property to the ModelBase to allow for composing a key based on a type and name.\u00a0 For example, a beer with a name \u201cOld Yankee Ale\u201d gets a key \u201cbeer_Old_Yankee_Ale.\u201d<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">protected<\/span> <span style=\"color: #0600ff;font-weight: bold\">virtual<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> BuildKey<span style=\"color: #008000\">(<\/span>T model<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Concat<\/span><span style=\"color: #008000\">(<\/span>model<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Type<\/span>, <span style=\"color: #666666\">&#8220;_&#8221;<\/span>, model<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Id<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Replace<\/span><span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8221; &#8220;<\/span>, <span style=\"color: #666666\">&#8220;_&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>The Get method takes the _id of the document as an argument when called.\u00a0 That value is then used as the key for calling the client\u2019s generic Get method.\u00a0 Another extension method \u2013 GetJson(string id) \u2013 is also being used by the Get method to convert the JSON document to an instance of T.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">virtual<\/span> T Get<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> id<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\nvar doc <span style=\"color: #008000\">=<\/span> _Client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">GetJson<\/span><span style=\"color: #008000\">&lt;<\/span>T<span style=\"color: #008000\">&gt;<\/span><span style=\"color: #008000\">(<\/span>id<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">if<\/span> <span style=\"color: #008000\">(<\/span>doc <span style=\"color: #008000\">!=<\/span> <span style=\"color: #0600ff;font-weight: bold\">null<\/span><span style=\"color: #008000\">)<\/span> doc<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Id<\/span> <span style=\"color: #008000\">=<\/span> id<span style=\"color: #008000\">;<\/span> <span style=\"color: #008080;font-style: italic\">\/\/server doesn&#8217;t pass back the _id in the JSON<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> doc<span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>Remove is very straightforward.\u00a0 It simply takes the document key (again, also the _id) and removes the item from Couchbase.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">virtual<\/span> <span style=\"color: #6666cc;font-weight: bold\">void<\/span> Remove<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> id<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n_Client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Remove<\/span><span style=\"color: #008000\">(<\/span>id<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>Providing base support for view access is done by convention in the View method.\u00a0 This method assumes that the design document name is the model type name pluralized.\u00a0 So BeerRepository will automatically have its view requests mapped to a design doc named \u201cbeers.\u201d\u00a0 The View method returns an IView instance.\u00a0 Since the HTTP call isn\u2019t actually made until a caller iterates over the IView, subclasses can call on the view using the fluent query methods.\u00a0 I\u2019ll have an example of a specific view call shortly.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">protected<\/span> IView<span style=\"color: #008000\">&lt;<\/span>IViewRow<span style=\"color: #008000\">&gt;<\/span> View<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> viewName<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> _Client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">GetView<\/span><span style=\"color: #008000\">(<\/span>InflectorNet<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Pluralize<\/span><span style=\"color: #008000\">(<\/span><a href=\"https:\/\/www.google.com\/search?q=typeof+msdn.microsoft.com\"><span style=\"color: #008000\">typeof<\/span><\/a><span style=\"color: #008000\">(<\/span>T<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Name<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">ToLower<\/span><span style=\"color: #008000\">(<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span>, viewName<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>There\u2019s also currently a SpatialView method, which allows for geospatial queries using GeoCouch.\u00a0 The GetSpatialView method of the client is currently experimental and hasn\u2019t been added to the client\u2019s 1.2 master branch.\u00a0 It\u2019ll be forthcoming however.\u00a0 If you clone the TapMap repository, you\u2019ll get a client binary with support for this method.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">protected<\/span> IView<span style=\"color: #008000\">&lt;<\/span>ISpatialViewRow<span style=\"color: #008000\">&gt;<\/span> SpatialView<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> viewName<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> _Client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">GetSpatialView<\/span><span style=\"color: #008000\">(<\/span>InflectorNet<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Pluralize<\/span><span style=\"color: #008000\">(<\/span><a href=\"https:\/\/www.google.com\/search?q=typeof+msdn.microsoft.com\"><span style=\"color: #008000\">typeof<\/span><\/a><span style=\"color: #008000\">(<\/span>T<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Name<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">ToLower<\/span><span style=\"color: #008000\">(<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span>, viewName<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>That covers the RepositoryBase.\u00a0 So now that we\u2019ve seen its methods and purpose, let\u2019s dig into a subclass.\u00a0 First, the User model class defines properties for Username, Email and Password.\u00a0 It also provides JSON property mappings to lowercased versions of the class properties.\u00a0 Notice also that User extends ModelBase and implements the Type property by returning the string \u201cuser.\u201d<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">\n<p><span style=\"color: #008000\">[<\/span>Serializable<span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #6666cc;font-weight: bold\">class<\/span> User <span style=\"color: #008000\">:<\/span> ModelBase<br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #008000\">[<\/span>Required<span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #008000\">[<\/span>JsonProperty<span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;username&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> Username <span style=\"color: #008000\">{<\/span> get<span style=\"color: #008000\">;<\/span> set<span style=\"color: #008000\">;<\/span> <span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #008000\">[<\/span>Required<span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #008000\">[<\/span>JsonProperty<span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;email&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> Email <span style=\"color: #008000\">{<\/span> get<span style=\"color: #008000\">;<\/span> set<span style=\"color: #008000\">;<\/span> <span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #008000\">[<\/span>Required<span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #008000\">[<\/span>JsonProperty<span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;password&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">]<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> Password <span style=\"color: #008000\">{<\/span> get<span style=\"color: #008000\">;<\/span> set<span style=\"color: #008000\">;<\/span> <span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">override<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> Type<br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\nget <span style=\"color: #008000\">{<\/span> <span style=\"color: #0600ff;font-weight: bold\">return<\/span> <span style=\"color: #666666\">&#8220;user&#8221;<\/span><span style=\"color: #008000\">;<\/span> <span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<\/div>\n<\/div>\n<p>The UserRepository class extends RepositoryBase with T being set to type User.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #6666cc;font-weight: bold\">class<\/span> UserRepository <span style=\"color: #008000\">:<\/span> RepositoryBase<span style=\"color: #008000\">&lt;<\/span>User<span style=\"color: #008000\">&gt;<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #008080;font-style: italic\">\/\/methods<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>With the simple definition above, the UserRepository has quite a bit of power.\u00a0 It can perform all of the basic CRUD functionality defined in its base class.\u00a0 However, there are some special scenarios for working with User documents in the app and the UserRepository adds methods to support these scenarios.<\/p>\n<p>When a user logs in with a username and password, one option would be to create a view that emits a composite key of username and password.\u00a0 However, a better alternative is to use the username and password to compose a key for the document.\u00a0 Such a key will allow us to retrieve a user document easily when the user logs in.\u00a0 This approach saves space by not having to create the secondary view index and allows for faster key by using the hashtable lookup.<\/p>\n<p>In the overridden Create method, the username (Id) and password (hashed) are used to create a key of the form user_Username_HashedPassword.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">public<\/span> <span style=\"color: #0600ff;font-weight: bold\">override<\/span> <span style=\"color: #6666cc;font-weight: bold\">ulong<\/span> Create<span style=\"color: #008000\">(<\/span>User model<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\nmodel<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Password<\/span> <span style=\"color: #008000\">=<\/span> HashHelper<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">ToHashedString<\/span><span style=\"color: #008000\">(<\/span>model<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Password<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\nmodel<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Id<\/span> <span style=\"color: #008000\">=<\/span> BuildKey<span style=\"color: #008000\">(<\/span>model<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\nvar result <span style=\"color: #008000\">=<\/span> _Client<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">CasJson<\/span><span style=\"color: #008000\">(<\/span>StoreMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Add<\/span>, BuildKey<span style=\"color: #008000\">(<\/span>model<span style=\"color: #008000\">)<\/span>, model<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> result<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Result<\/span> <span style=\"color: #008000\">?<\/span> result<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Cas<\/span> <span style=\"color: #008000\">:<\/span> <span style=\"color: #ff0000\">0<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>BuildKey is also overridden to allow for the new key format. \u00a0\u00a0The buildKey private method is needed by the overloaded Get method that we\u2019ll see shortly.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">\n<p><span style=\"color: #0600ff;font-weight: bold\">protected<\/span> <span style=\"color: #0600ff;font-weight: bold\">override<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> BuildKey<span style=\"color: #008000\">(<\/span>User user<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> buildKey<span style=\"color: #008000\">(<\/span>user<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Username<\/span>, user<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Password<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">private<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span> buildKey<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> username, <span style=\"color: #6666cc;font-weight: bold\">string<\/span> password<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> <span style=\"color: #6666cc;font-weight: bold\">string<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Concat<\/span><span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;user_&#8221;<\/span>, username, <span style=\"color: #666666\">&#8220;_&#8221;<\/span>, password<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<\/div>\n<\/div>\n<p>The Get method as defined in RepositoryBase assumes a lookup by key.\u00a0 Rather than expose the special user key format to the calling UserController class, Get is overloaded to accept a username and password from which the new key is composed.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\"><span style=\"color: #0600ff;font-weight: bold\">public<\/span> User Get<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> username, <span style=\"color: #6666cc;font-weight: bold\">string<\/span> password<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> Get<span style=\"color: #008000\">(<\/span>buildKey<span style=\"color: #008000\">(<\/span>username, HashHelper<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">ToHashedString<\/span><span style=\"color: #008000\">(<\/span>password<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/div>\n<\/div>\n<p>The UserRepository class is also responsible for helping to answer the questions of whether a username or email is unique.\u00a0 To so do, two views are used.\u00a0 The first simply emits email as key for all user documents; the second emits the username as key.\u00a0 There are more clever ways to create these indexes, but to keep things simple, there\u2019s a one-to-one mapping between the property to be checked and its view.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">\n<p>function <span style=\"color: #008000\">(<\/span>doc<span style=\"color: #008000\">)<\/span> <span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">if<\/span> <span style=\"color: #008000\">(<\/span>doc<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">type<\/span> <span style=\"color: #008000\">==<\/span> <span style=\"color: #666666\">&#8220;user&#8221;<\/span><span style=\"color: #008000\">)<\/span> <span style=\"color: #008000\">{<\/span><br \/>\nemit<span style=\"color: #008000\">(<\/span>doc<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">email<\/span>, <span style=\"color: #0600ff;font-weight: bold\">null<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<p>function <span style=\"color: #008000\">(<\/span>doc<span style=\"color: #008000\">)<\/span> <span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">if<\/span> <span style=\"color: #008000\">(<\/span>doc<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">type<\/span> <span style=\"color: #008000\">==<\/span> <span style=\"color: #666666\">&#8220;user&#8221;<\/span><span style=\"color: #008000\">)<\/span> <span style=\"color: #008000\">{<\/span><br \/>\nemit<span style=\"color: #008000\">(<\/span>doc<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">usrename<\/span>, <span style=\"color: #0600ff;font-weight: bold\">null<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<\/div>\n<\/div>\n<p>The UserRepository defines GetByEmail and GetByUsername methods, which both use the base View method to query their respective views.\u00a0 In both methods, the limit is set to 1 and there\u2019s a hard return on the first iteration since we care only that a single item exists with this property value.\u00a0 Stale views are not allowed, because we are trying to enforce uniqueness of data and we need to make sure we have the most up to date view index possible.<\/p>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace\">\n<p><span style=\"color: #0600ff;font-weight: bold\">public<\/span> User GetByEmail<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> email<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">foreach<\/span> <span style=\"color: #008000\">(<\/span>var item <span style=\"color: #0600ff;font-weight: bold\">in<\/span> View<span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;by_email&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Limit<\/span><span style=\"color: #008000\">(<\/span><span style=\"color: #ff0000\">1<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Key<\/span><span style=\"color: #008000\">(<\/span>email<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Stale<\/span><span style=\"color: #008000\">(<\/span>StaleMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0600ff;font-weight: bold\">False<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> Get<span style=\"color: #008000\">(<\/span>item<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">ItemId<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> <span style=\"color: #0600ff;font-weight: bold\">null<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<p><span style=\"color: #0600ff;font-weight: bold\">public<\/span> User GetByUsername<span style=\"color: #008000\">(<\/span><span style=\"color: #6666cc;font-weight: bold\">string<\/span> username<span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">foreach<\/span> <span style=\"color: #008000\">(<\/span>var item <span style=\"color: #0600ff;font-weight: bold\">in<\/span> View<span style=\"color: #008000\">(<\/span><span style=\"color: #666666\">&#8220;by_username&#8221;<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Limit<\/span><span style=\"color: #008000\">(<\/span><span style=\"color: #ff0000\">1<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Key<\/span><span style=\"color: #008000\">(<\/span>username<span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">Stale<\/span><span style=\"color: #008000\">(<\/span>StaleMode<span style=\"color: #008000\">.<\/span><span style=\"color: #0600ff;font-weight: bold\">False<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">)<\/span><br \/>\n<span style=\"color: #008000\">{<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> Get<span style=\"color: #008000\">(<\/span>item<span style=\"color: #008000\">.<\/span><span style=\"color: #0000ff\">ItemId<\/span><span style=\"color: #008000\">)<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><br \/>\n<span style=\"color: #0600ff;font-weight: bold\">return<\/span> <span style=\"color: #0600ff;font-weight: bold\">null<\/span><span style=\"color: #008000\">;<\/span><br \/>\n<span style=\"color: #008000\">}<\/span><\/p>\n<\/div>\n<\/div>\n<p>I\u2019ll explore the UserController at another time to show how it all fits together.\u00a0 My goal with this post was to introduce the RepositoryBase and how it\u2019s extended.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I\u2019ve been meaning to put together a reference application for using .NET and Couchbase Server.\u00a0 While traveling to London for the Progressive NoSQL conference at Skills Matter, I passed the hours waiting for my hotel room to be ready by [&hellip;]<\/p>\n","protected":false},"author":22,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"ppma_author":[8980],"class_list":["post-1804","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"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>Repository of T for Couchbase using the .NET Client Library<\/title>\n<meta name=\"description\" content=\"This post introduces to the RepositoryBase and how it\u2019s extended and how to create a simple Repository of T for Couchbase using the .NET Client Library.\" \/>\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\/ko\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"TapMap Part I: Working with a Repository of T with Couchbase Server 2.0 and the .NET Client Library\" \/>\n<meta property=\"og:description\" content=\"This post introduces to the RepositoryBase and how it\u2019s extended and how to create a simple Repository of T for Couchbase using the .NET Client Library.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/ko\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T18:04:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-06-28T08:20:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/sites\/default\/files\/uploads\/all\/images\/tapmap_0.PNG\" \/>\n<meta name=\"author\" content=\"John Zablocki, NET. SDK Developer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"John Zablocki, NET. SDK Developer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/\"},\"author\":{\"name\":\"John Zablocki, NET. SDK Developer, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/ee312fb775c13d20a32f1d455888a282\"},\"headline\":\"TapMap Part I: Working with a Repository of T with Couchbase Server 2.0 and the .NET Client Library\",\"datePublished\":\"2014-12-16T18:04:10+00:00\",\"dateModified\":\"2023-06-28T08:20:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/\"},\"wordCount\":1952,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/\",\"name\":\"Repository of T for Couchbase using the .NET Client Library\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T18:04:10+00:00\",\"dateModified\":\"2023-06-28T08:20:48+00:00\",\"description\":\"This post introduces to the RepositoryBase and how it\u2019s extended and how to create a simple Repository of T for Couchbase using the .NET Client Library.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"TapMap Part I: Working with a Repository of T with Couchbase Server 2.0 and the .NET Client Library\"}]},{\"@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\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@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\\\/ee312fb775c13d20a32f1d455888a282\",\"name\":\"John Zablocki, NET. SDK Developer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g201925d9efc4992ce80385b76fdea34b\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g\",\"caption\":\"John Zablocki, NET. SDK Developer, Couchbase\"},\"description\":\"John Zablocki is a NET. SDK Developer at Couchbase. John is also the organizer of Beantown ALT.NET and a former adjunct at Fairfield University. You can also check out the book on Amazon named \\\"Couchbase Essentials\\\" which explains how to install and configure Couchbase Server.\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/author\\\/john-zablocki\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Repository of T for Couchbase using the .NET Client Library","description":"\uc774 \uac8c\uc2dc\ubb3c\uc5d0\uc11c\ub294 \ub9ac\ud3ec\uc9c0\ud1a0\ub9ac\ubca0\uc774\uc2a4\uc640 \uc774\ub97c \ud655\uc7a5\ud558\ub294 \ubc29\ubc95, \uadf8\ub9ac\uace0 .NET \ud074\ub77c\uc774\uc5b8\ud2b8 \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud558\uc5ec \uac04\ub2e8\ud55c T for Couchbase \ub9ac\ud3ec\uc9c0\ud1a0\ub9ac\ub97c \ub9cc\ub4dc\ub294 \ubc29\ubc95\uc744 \uc18c\uac1c\ud569\ub2c8\ub2e4.","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\/ko\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/","og_locale":"ko_KR","og_type":"article","og_title":"TapMap Part I: Working with a Repository of T with Couchbase Server 2.0 and the .NET Client Library","og_description":"This post introduces to the RepositoryBase and how it\u2019s extended and how to create a simple Repository of T for Couchbase using the .NET Client Library.","og_url":"https:\/\/www.couchbase.com\/blog\/ko\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T18:04:10+00:00","article_modified_time":"2023-06-28T08:20:48+00:00","og_image":[{"url":"https:\/\/www.couchbase.com\/blog\/sites\/default\/files\/uploads\/all\/images\/tapmap_0.PNG","type":"","width":"","height":""}],"author":"John Zablocki, NET. SDK Developer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"John Zablocki, NET. SDK Developer, Couchbase","Est. reading time":"9\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/"},"author":{"name":"John Zablocki, NET. SDK Developer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ee312fb775c13d20a32f1d455888a282"},"headline":"TapMap Part I: Working with a Repository of T with Couchbase Server 2.0 and the .NET Client Library","datePublished":"2014-12-16T18:04:10+00:00","dateModified":"2023-06-28T08:20:48+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/"},"wordCount":1952,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Uncategorized"],"inLanguage":"ko-KR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/","url":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/","name":"Repository of T for Couchbase using the .NET Client Library","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T18:04:10+00:00","dateModified":"2023-06-28T08:20:48+00:00","description":"\uc774 \uac8c\uc2dc\ubb3c\uc5d0\uc11c\ub294 \ub9ac\ud3ec\uc9c0\ud1a0\ub9ac\ubca0\uc774\uc2a4\uc640 \uc774\ub97c \ud655\uc7a5\ud558\ub294 \ubc29\ubc95, \uadf8\ub9ac\uace0 .NET \ud074\ub77c\uc774\uc5b8\ud2b8 \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud558\uc5ec \uac04\ub2e8\ud55c T for Couchbase \ub9ac\ud3ec\uc9c0\ud1a0\ub9ac\ub97c \ub9cc\ub4dc\ub294 \ubc29\ubc95\uc744 \uc18c\uac1c\ud569\ub2c8\ub2e4.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/"]}]},{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/tapmap-part-i-working-repository-t-couchbase-server-20-and-net-client-library\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"TapMap Part I: Working with a Repository of T with Couchbase Server 2.0 and the .NET Client Library"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","description":"NoSQL \ub370\uc774\ud130\ubca0\uc774\uc2a4, Couchbase","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":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@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\/ee312fb775c13d20a32f1d455888a282","name":"\uc874 \uc790\ube14\ub85c\ud0a4, NET. SDK \uac1c\ubc1c\uc790, Couchbase","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/secure.gravatar.com\/avatar\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g201925d9efc4992ce80385b76fdea34b","url":"https:\/\/secure.gravatar.com\/avatar\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g","caption":"John Zablocki, NET. SDK Developer, Couchbase"},"description":"John Zablocki is a NET. SDK Developer at Couchbase. John is also the organizer of Beantown ALT.NET and a former adjunct at Fairfield University. You can also check out the book on Amazon named \"Couchbase Essentials\" which explains how to install and configure Couchbase Server.","url":"https:\/\/www.couchbase.com\/blog\/ko\/author\/john-zablocki\/"}]}},"acf":[],"authors":[{"term_id":8980,"user_id":22,"is_guest":0,"slug":"john-zablocki","display_name":"John Zablocki, NET. SDK Developer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/8c5a77152c796c424a3f7f6d9fa31a999a7fe115d64c2acc93c4c0c014e6512a?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/1804","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/comments?post=1804"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/1804\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media?parent=1804"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/categories?post=1804"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/tags?post=1804"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/ppma_author?post=1804"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}