Search:

Search all manuals
Search this manual
Manual
Couchbase Client Library: .NET (C#) 1.2
Community Wiki and Resources
Wiki: .NET Client Library
Download Client Library
.NET Client Library
Couchbase Developer Guide 2.0
Couchbase Server Manual 2.0
SDK Forum
Additional Resources
Community Wiki
Community Forums
Couchbase SDKs
Parent Section
2 Couchbase and ASP.NET MVC
Chapter Sections
Chapters

2.8. Brewery Forms

With the new methods implemented, it's time to create the scaffolding for the CRUD forms. The first task will be to create an edit form. Open the BreweriesController and locate the Edit methods that were generated by the Add Controller wizard.

In the HTTP GET override of Edit, modify it as shown below. This action will retrieve the Brewery and pass it to the view as the model. Note the change from an int id parameter to a string id parameter.

public ActionResult Edit(string id)
{
    var brewery = BreweryRepository.Get(id).Item1;
    return View(brewery);
}

Update the Edit method that handles POSTs as shown below. Validation and error handling are intentionally being omitted for brevity.

[HttpPost]
public ActionResult Edit(string id, Brewery brewery)
{
    BreweryRepository.Update(brewery);
    return RedirectToAction("Index");
}

The edit form will be created using scaffolding, as was the case with the listing page. Right click on the “Breweries” folder in the “Views” directory and click Add -> View. Name the view “Edit” and strongly type it to a Brewery with Edit scaffolding.

Figure 2.10. Figure 10, Create the Edit view

Create the edit view

Rebuild the application and return to the brewery listing page.  Click on an “Edit” link and you should see the edit form loaded with the details for that brewery.  Edit some values on the form and click save. You should see your changes persisted on the listing page.

Figure 2.11. Figure 11, Create the Edit view

Create the edit view

The Details action looks very much like Edit. Get the Brewery and provide it as the model for the view.

public ActionResult Details(string id)
{
    var brewery = BreweryRepository.Get(id).Item1;
    return View(brewery);
}

Create a scaffolding form for Details using the same process as was used with Edit.

Figure 2.12. Figure 12, Create the Details view

Create the details view

Rebuild and return to the list page. Click on a "Details" link. You should see a page listing the data for that brewery.

Figure 2.13. Figure 13, Create the details view

Create the details view

The Create and Edit actions of the BreweriesController are quite similar, save for the fact that Create's GET method doesn't provide a model to the view. Again, error handling and validation are being omitted for brevity's sake.

public ActionResult Create()
{
    return View();
}
[HttpPost]
public ActionResult Create(Brewery brewery)
{
    BreweryRepository.Create(brewery);
    return RedirectToAction("Index");
}

Go through the scaffolding process again to add a create view for the Create action.  Rebuild and click the “Create New” link on the list page to test the new form.  Breweries (for now) are sorted by key and limited to 50, so you might not see yours in the list.  If you want to verify your create action worked, use brewery name that starts with a numeric value (e.g., 123 Brewery).

Another reason you wouldn't see your new brewery appear in the list of breweries is that the view is set to allow stale (eventually consistent) results.  In other words, the incremental update to the “all” index would be performed after the query.  If you refresh, you should see your brewery in the list. 

Allowing the breweries to be sorted by key is convenient, since the key is based on the breweries name.  However, if case-sensitivity is important in sorting or the key creation strategy changes, then explicitly sorting on the brewery's name is a better idea.  To that end, creating a new view indexed on the Brewery name is the right approach.

The new map function will look similar to the “all” map function, but will add tests on “doc.name” and will emit the doc.name as the key. 

function(doc, meta) {
	if (doc.type == "brewery" && doc.name) {
		emit(doc.name, null);
	}
}

If you are using the web console to manage your design documents, save the map function above as “by_name” in the “breweries” design document.  If you are using the Model Views framework, add an attribute to the Name property of Brewery>.  Then compile and run your application. 

Adding the CouchbaseViewKey attribute will create the view above.  The first argument is the name of the view.  The second is the name of the JSON document property to emit as key. 

[CouchbaseViewKey("by_name", “name”)]
public string Name { get; set; }

The next step is to replace the GetAll call with a call to the new view.  First, add a protected method in RepositoryBase that returns a typed view instance, set with the design doc for that model type.  The isProjection flag is set when the type of T does not properties of the JSON to properties of the class.  It must be used with explicit JSON.NET mappings.

protected IView<T> GetView(string name, bool isProjection = false)
{
    return _Client.GetView<T>(_designDoc, name, ! isProjection);
}

Then in BreweryRepository, implement GetAllByName as shown below. This new method simply returns the view, optionally allowing a limit and stale results.

public IEnumerable<Brewery> GetAllByName(int limit = 0, bool allowStale = false)
{
    var view = GetView("by_name");
    if (limit > 0) view.Limit(limit);
    if (! allowStale) view.Stale(StaleMode.False);
    return view;
}

Next, modify the BreweriesController so that the Index action calls the new GetAllByName method.

public ActionResult Index()
{
    var breweries = BreweryRepository.GetAllByName(50);
    return View(breweries);
}

Compile and run your application.  The list page might be ordered a little differently as the sample database did scrub some keys of punctuation and other non-word or non-digit characters.  Also now (because of the stale setting), if you create a new Brewery, it should appear after a redirect and should not require a refresh.

Note that it is still possible that the view didn't consider the new Brewery when it was executed with state set to false.  If the document hadn't persisted to disk before the index was updated, it wouldn't have been included. 

If that level of consistency is important to your application, you should use an overload of ExecuteStore that includes durability requirements.  See the documentation on ExecuteStore for more information.

The last piece required to complete the CRUD functionality for breweries is to implement the delete form.  Update the Delete actions in BreweriesController as shown below.

public ActionResult Delete(string id)
{
    var brewery = BreweryRepository.Get(id).Item1;
    return View(brewery);
}
[HttpPost]
public ActionResult Delete(string id, Brewery brewery)
{
    BreweryRepository.Delete(id);
    return RedirectToAction("Index");
}

To create the delete form, simply go through the Add View process again and choose scaffolding for delete (don't forget to choose the Brewery model).