BTI420 Lab 4

Work with a database-hosted persistent store. Use a two-entity domain model.

.

BTI420 Lab 4 – Due on Tue Feb 10

Due date: Tuesday, February 10, 2015, at 7:30am ET

Grade value: 4% of your final course grade

.

Objective(s)

Work with a persistent store, and its program code components.

Get data from a browser user to add objects to the persistent store.

Continue to use and configure scaffolding when appropriate and useful.

Continue to use and configure HTML Helpers when appropriate and useful.

.

Introduction to the problem that you will solve

We need a web app that will enable a retail store worker to add new products that customers can buy.

The domain model is Suppliers and Products. 

Your web app will create a small number of Supplier objects when launched for the first time. It will also have a controller that will deliver a collection to a default view, and render that collection as a list (or more specifically, an HTML Table).

Your web app will enable the user to manage Product objects. Its ‘products’ controller will support these tasks:

  • Display all products (in a list/table)
  • Display one selected product
  • Add new product

Obviously, you will write views that render content (where appropriate).

Also, a ‘manager’ object will manage / mediate / coordinate / marshal data operations.

Read through this assignment fully before starting work on it. That way you will know what’s coming.

Display all products…

browser-products-list

.

Display one selected product…

browser-product-detail

.

Add new product…

browser-product-add

.

Get started with Lab 4

You should use the “Lab 4 base project”, which is in the Assignment area of the My.Seneca/Blackboard portal.

It works correctly, and has starter data for two suppliers. The suppliers controller is also complete, and its supporting view models and manager class methods. Study the existing code to get oriented.

.

Look at the code for the persistent store components

As you recently learned, look at the code for the persistent store components.

  1. The References item will contain the Entity Framework library
  2. The connection string is in the project’s Web.config
  3. Partially-written model classes for Supplier and Product are in the Models folder
  4. Also, look at the data context class
  5. Study the store initializer class, and the code that will create supplier objects

Confirm that your project has these components, so that it is ready for the remaining work.

.

Design model classes

design-model-classesThe existing Supplier design model class has these properties:

  • Id – int – identifier
  • Name – string
  • TypeOfBusiness – string
  • Country – string – head office location
  • NameOfCEO – string
  • YearStarted – int
  • Products – collection of Product

It (obviously) also has a default constructor.

The Product design model class needs these properties:

  • Id – int – identifier
  • Name – string
  • ProductId – string – part/model identifier
  • Size – string
  • UPC – string – universal product code
  • MSRP – double – suggested retail price
  • Supplier – Supplier

.

Incidentally, the diagram at the right was created in Visual Studio. The wrench icon glyph-property is a property. A box icon glyph-method is a method (which is usually the default constructor). The associations among the classes are shown with arrows; notice the single arrowhead for ‘to one’, and the double arrowhead for ‘to many’.

.

Existing view model classes for Supplier

Two have been created for this web app:

  1. SupplierList, with only the data needed in a user interface ‘select/list’ control
  2. SupplierBase, with most properties

SupplierList has the Id property, and another property that’s useful when displayed in, for example, a drop-down list.

vm-supplierlist

SupplierBase has most properties, but it does not need navigation properties.

vm-supplierbase

These two classes do NOT have an inheritance relationship.

.

Enable a browser user to ‘add a new product’

The most important use case is the ability of a user to create a new Product object.

This interaction has three steps or tasks:

  1. Display a data entry form
  2. Gather user input
  3. Display the result

Each will require a view model class:

Step / Task View model class, suggested name
1. Display a data entry form ProductAddForm
2. Gather user input ProductAdd
3. Display the result ProductBase

.

The following illustrates some of the important concepts behind task 1.

(Click to view it full-size in a tab/window.)

map-productaddform-to-view

 

.

An example form is shown below:

browser-form-product

.

Name, ProductId, and UPC will be string properties. MSRP will be a double.

What about the radio button group, and the drop-down list user interface controls?

What data do we send to render the view?

We send a SelectList object for each control.

Review this document now for more about configuring a view model object with a SelectList object.

Welcome back. We will cover each scenario now.

.

Radio button group (single select) – simple collection of strings

In this scenario…

We want to render a single-selection radio button group (HTML <input type=radio>).

The data source will be a collection of strings that are generated from the manager object.

When the form is posted, the selected string will be sent (to the controller method).

.

Planning and preparations

We will complete these steps:

  • Write a ‘product add form’ view model
  • Write a ‘product add’ view model
  • Plan the data for the radio button group
  • Plan the controller method that displays the form to the browser user
  • Plan the view code
  • Plan the controller method that handles the data posted from the browser user

.

Radio button group – implementation

Do the following.

.

Write a ‘product add form’ view model 

The purpose of this view model class is to describe an object that will deliver the data needed to render the view.

Before you write the view model class, think about the use case – enable a user to add a new product. To do that, you must display an HTML Form.

Now you’re ready to write the view model class. As suggested above, the name of the view model class will be ProductAddForm. Copy the properties from the Product design model class, then edit:

  • change the Size property type to SelectList
  • change the Supplier property type to SelectList

It will look like this after your edits:

vm-class-productaddform

.

Write a ‘product add’ view model 

The purpose of this view model class is to describe an object that is posted by the browser user.

As suggested above, the name of the view model class will be ProductAdd. Copy the properties from the Product design model class, then edit:

  • change the name of the Supplier property to SupplierId, and
  • change the SupplierId property type to int

It will look like this after your edits:

vm-class-productadd

.

Plan the data for the radio button group 

As noted above, the radio button group data source will be a collection of strings that are generated from the manager object.

Edit the Manager class, and add code to create and return a simple List<string> of ‘size’ strings: Small, Medium, and Large. (In other scenarios, it is possible that these strings would be generated dynamically).

.

Plan the controller method that displays the form to the browser user 

Create an ‘product add form’ view model object. Configure it with the data needed in the user interface:

controller-code-prepare-rbg-data

(The ‘product add form’ object will be passed to the view later.)

.

Plan the view code 

Use the ‘scaffolding’ feature to add a “Create” view. Its model class will be “ProductAddForm”.

As you will see, the scaffolder will not generate the radio button group (or the dropdown list that we need later). You must add that code yourself.

The value of the “name” attribute on the <input> element must match the name of the property in the ProductAdd view model (“Size”).

view-code-render-rbg-data

.

Plan the controller method that handles the data posted from the browser user

The selected value from the radio button group is posted back as a string, in the “Size” property of the ProductAdd view model class. It matches the name and type of the property in the Product design model class.

When the HTML Form posts back to the server, the posted data will include data that looks like this:
Size=Medium

Therefore, we do not have to do anything special here.

.

Dropdown list (single select) – collection of complex objects

In this scenario…

We want to render a single-selection dropdown list (HTML <select>).

The data source will be a collection of SupplierList objects that are generated from the manager object.

When the form is posted, the integer value of the selected will be sent (to the controller method).

.

Planning and preparations

We will complete these steps:

  • Write a ‘product add form’ view model done (above)
  • Write a ‘product add’ view model done (above)
  • Plan the data for the radio button group
  • Plan the controller method that displays the form to the browser user
  • Plan the view code
  • Plan the controller method that handles the data posted from the browser user
  • Plan the manager method that handles the ‘add new’ request

.

Dropdown list – implementation

Do the following.

.

Plan the data for the dropdown list 

As noted above, the dropdown list data source will be a collection of SupplierList objects that are generated from the manager object.

Edit the Manager class, and add code to return a collection of SupplierList objects.

.

Plan the controller method that displays the form to the browser user 

Add to the method you started coding above. Configure it with the data needed in the user interface. Make sure that you use the constructor that enables you to specify the ‘value’ and ‘text’ field names:

controller-code-prepare-ddl-data

.

Plan the view code 

Add to the code you started above. You must add the code that renders the dropdown list yourself.

The value of the first argument to the dropdown list helper must match the name of the property in the ProductAdd view model (“SupplierId”).

view-code-render-ddl-data

.

Plan the controller method that handles the data posted from the browser user 

The selected value from the dropdown list is posted back as a string (but it is an integer), in the “SupplierId” property of the ProductAdd view model class. It does NOT match the name and type of a property in the Product design model class. However, we will use that value (in a manager ‘add new’ method) to fetch the Supplier object, and assign it as a property when we create a new Product object.

When the HTML Form posts back to the server, the posted data will include data that looks like this:
SupplierId=123

The following illustrates some of the important concepts behind task 2.
(Click to view it full-size in a tab/window.)

map-productadd-to-controller

 

.

Plan the manager method that handles the ‘add new’ request

The first task must be to validate the incoming SupplierId value. Therefore, attempt to fetch a single Supplier object, using the SupplierId value. If null, return null, otherwise continue.

In the past, you used the SingleOrDefault() method to fetch a single matching object from the persistent store. You can continue to use that.

However, you can now use the Find() method, when working with the primary key property (the one named “Id” or “<entityName>Id”).

Its syntax is simpler. Its argument is the value of the primary key. Compare the following:


var supplier = ds.Suppliers.SingleOrDefault(i => i.Id == newItem.SupplierId);

var supplier = ds.Suppliers.Find(newItem.SupplierId);

.

Create a new Product object, and use code to map the incoming ProductAdd object to the Product object. Make sure that you set the Product object’s “Supplier” property to the Supplier object you just fetched above.

Add the new Product object to the persistent store collection (and make sure that you save changes).

Next, create a ProductBase object, and use code to map the Product object to the ProductBase object.

Return the ProductBase object.

.

Other tasks that need to be done

These include:

  • Write the ProductBase view model class
  • Edit the Manager class
  • ProductsController – Index() method and view
  • ProductsController – Details(int id) method and view
  • Configure (fix) navigation in your web app

.

ProductBase view model class

The purpose of this view model class is to describe the object that will be delivered to a view, for display in a list (i.e. an HTML Table) or on its own.

ProductBase inherits from ProductAdd, and therefore has all its properties. In addition, it has two more:

  • Id – int – the object identifier
  • SupplierName – string – the value of the Name property in the Supplier of the Product object

As suggested above, the name of the view model class will be ProductBase. It will look like this:

vm-productbase

.

Edit the Manager class

Finish coding these methods:

public IEnumerable<ProductBase> GetAllProducts()

public ProductBase GetProductById(int id)

public ProductBase AddNewProduct(ProductAdd newItem)

public List<string> GetProductSizes()

.

“Get all products” method

Get all Product objects from the persistent store, sorted by name.

New: When you fetch the Product objects, you must also fetch the associated Supplier object, using the Include() method:


var fetchedObjects = ds.Products.Include("Supplier").OrderBy(nm => nm.Name);

 

.

Use AutoMapper to return the collection as ProductBase objects.

.

“Get specific product by its identifier” method

Attempt to fetch a single Product object, using the passed-in identifier. If null, return null. Otherwise, continue.

New: When you fetch the Product object, you must also fetch the associated Supplier object, using the Include() method:


var fetchedObject = ds.Products.Include("Supplier").SingleOrDefault(i => i.Id == id);

.

Use AutoMapper to return the object as a ProductBase object.

.

“Add a new product” method

The first task must be to validate the incoming SupplierId value. Therefore, attempt to fetch a single Supplier object, using the SupplierId value. If null, return null, otherwise continue.

Create a new Product object, and use code to map the incoming ProductAdd object to the Product object. Make sure that you set the Product object’s “Supplier” property to the Supplier object you just fetched above.

Add the new Product object to the persistent store collection (and make sure that you save changes).

Finally, use AutoMapper to return the object as a ProductBase object.

.

ProductsController – Index() method and view

Call the manager object’s “get all products” method.

Return the results to the view.

Add a view. You can (should) use scaffolding. Use the “List” template. Select “ProductBase” as the model class.

You can edit the view if you wish to improve it.

.

ProductsController – Details(int id) method and view

Call the manager object’s “get specific product by its identifier” method.

If null, redirect to the index view.

Otherwise, return the fetched object to the view.

Add a view. You can (should) use scaffolding. Use the “Details” template. Select “ProductBase” as the model class.

.

Configure (fix) navigation in your web app

Add links to the new page hierarchy in an appropriate place.

Maybe on the web app’s (Home) Index.cshtml view (in the body). Maybe also in the menu in _Layout.cshtml.

.

Submit your work on My.Seneca/Blackboard

The instructions are similar to those from Lab 1. Here’s a brief version:

1. Make a copy of your work, and remove the packages, bin, and obj folders.

2. Create a compressed (zip) version of your solution’s folder.

3. Login to My.Seneca/Blackboard

4. Navigate to the BTI420 Assignments area, and use the link to upload/submit your work

.

.

.

.

.

.

.

.

.

.

.

.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: