BTI420 notes – Wed Feb 12

Edit and delete patterns. Working with dates and times. Associations other than one-to-many.

.

Edit pattern

Performing an edit on content within your app is done in a very similar manner to the ‘add new’ task we have already learned. You create two view models, one for generating the edit form and the other for handling the POST action.

General approach:

  1. Create view model classes
  2. Write two controller methods to service the GET and POST requests
  3. Write the manager method to process the edit request

The EditAndDelete web app code example, in the GitHub repository, will help you learn about both patterns.

.

View model classes

Look at an entity object’s properties, and decide which are to be editable.

Create a view model class (e.g. ProductEditForm) to send to the HTML Form on the view, which holds:

  1. the object identifier,
  2. the editable properties, and
  3. anything else that needs to be rendered (e.g. SelectList for a UI control for the Sizes and Suppliers).

Note that we can use data annotations to pass content that we don’t want edited by the user into the HTML Form. For example: [Hidden], [ReadOnly(true)], etc.

Next, create a view model class (e.g. ProductEdit) for the object that the user will post back.

.

Controller methods

The edit pattern requires a GET method and a POST method, similar to the ‘add new’ functionality.

In the GET method, create and configure the object to send to the view, and do it.

In the POST method, two verification checks should always be performed.

The first checks whether the incoming object passes ModelState.IsValid. The second checks whether the identifier in the URI matches the identifier in the posted object. If both these checks pass, send it along to the manager object method that does the work. Handle the return value in an appropriate way.

What’s appropriate? It depends upon your use case. It may be acceptable to do any of the following:

  1. Display the edited object in a ‘details’ view
  2. Return to a ‘list’ view
  3. Return the ‘edit’ HTML Form again for additional editing tasks

If either check fails, return the ‘edit’ view, which will tell the user what to fix.

.

Manager method

In the manager class method, handle the editing request by doing the following:

  1. Extract the object identifier from the passed-in object
  2. Locate the object in the data store; use the Find() method
  3. Update the object’s information
  4. Save the changes back to the data store
  5. Return the edited object

.

The fetched object offers a very nice SetValues() method that performs task 3 above. For example:

ds.Entry(fetchedObject).CurrentValue.SetValues(newItem);

It examines fetchedObject, and performs a property-matching task (name and data type). On a match, if the values are different, an update is performed. (If the values are the same, it moves on to the next property. Navigation properties are ignored. Extra properties are ignored. Missing properties are ignored. The ‘ignore’ result does not raise an exception.

Later in the course, we will learn how to enable this kind of operation for authorized users only.

.

Possible code examples

Simple, one entity in the design model – maybe the “Surveys” example (that uses a persistent store)

Associated entities, maybe the Manufacturers-Vehicles design model

Associated entities, using the edit form to select items to include in a collection property

.

Delete pattern

Like the ‘add’ and ‘edit’ patterns, this is often done as a GET and POST pair.

We display an HTML Form to the user, prompting them to confirm that yes, they want to delete the object. Create a view model object with enough information for the user to make a decision.

The delete handler method performs one or more validity checks, and then calls a manager method to perform the delete.

The manager method, in our initial design approach, returns a bool result. If you wish, you can use that to return an appropriate result to the user.

The above approach would permanently delete the object from the persistent storage. This is not always a good thing. In most systems, it is better to design based on setting a delete flag in the data. The code discussed in class would be similar, except the Remove() method would not be used. Instead you would “Edit” the object and set the delete flag (which would be a parameter in your design model class) to “True”. All your LINQ statements would then take into account this “delete” flag when doing queries for information.

Later in the course, we will learn how to enable this kind of operation for authorized users only.

.

Working with dates and times

Working with dates and times is hard. Especially on the web.

The .NET Framework has a DateTime structure to represent an instant in time. It is a rich object, with many capabilities. However, we will use a handful. Scan the reference documentation and locate the members that are interesting to you. They will include:

  • constructor(s)
  • Now property
  • ToString() method
  • ToLongDateString() and ToLongTimeString() methods

.

Topics that we discussed during the class session:

  • Working with a DateTime in code; create from Now, create from user-provided data.
  • Popular to-string methods. Basic date arithmetic.
  • Dates on the world wide web. GMT. Local time. Offset.
  • Dates in HTML5 (and in modern browsers). Display. Input from user. Browser widget assists. Visually good in Chrome. Not so good in other browsers.
  • Dates in a persistent store like our database server, SQL Server. datetime, datetime2.
  • Improving date handling in a browser, with Boostrap ‘datepicker’.
  • Data annotation that helps with display formatting: DisplayFormat
  • Date and time format strings: Standard, and Custom

.

The DatesAndTimes web app code example, in the GitHub repository, will help you learn about dates and times.

.

Bootstrap ‘datepicker’

The web app code example uses a date picker to help the user enter a date. Here’s how to use it.

First, use NuGet to locate and install the Bootstrap Datepicker.

nuget-boostrap-datepicker

After installation, look in the Scripts folder, and you’ll see that it’s there.

Next, in AppStart, edit the BundlesConfig.cs source code file. Add the date picker to the ‘bootstrap’ bundle. (Don’t worry about understanding this right now; we’ll cover the purpose of bundles in class soon.)

edit-bundles-config

Create a new JavaScript source code file, named “appHelpers.js”, and save it in the Scripts folder. Although we can include JavaScript in the view source code, it’s a best practice to do it this way. The code will look like this:

apphelpers-javascript

This code will add date picker support to the HTML element with the matching value for the ‘id’ attribute. Check out the view model class property names – that’s where these values come from.

At the bottom of the create view, you will already have a Scripts section. Add a reference to the ‘appHelpers.js’ code file:

create-reference

When the ‘create’ view appears, and the user focuses the input cursor in the date field, a date picker will pop up, on ANY browser:

screenshot

.

Association – many-to-many

Many problem domains have a “many to many” relationship among entities.

In our classes, we simply create collection properties for both ends of a many-to-many association.

assoc-many-to-many

Then, we perform data operations by using the same technique that’s used for the “to-many” end of a one-to-many association.

View model classes: Create a view model class that includes a collection property for the associated entity. Its type must be a collection of another view model type. For example:

  • MovieBase – typical movie view model class, with the identifier, and all or most properties
  • MovieBaseWithActors – inherits from MovieBase, adds an ICollection<ActorBase> property; its name MUST match the design model class property name (e.g. “Actors”) for AutoMapper to do its job correctly

Manager: When fetching an object, use the Include() method if you want to include the associated object(s) in the fetch. You’ve done this before. Make sure that the method’s return type is correct (e.g. IEnumerable<MovieBaseWithActors>).

AutoMapper: Define your maps as you have learned. No special steps are required. When the map is executed, the associated collection will be correctly processed.

Study the ManyToMany web app code example on the GitHub code repository.

.

Association – self-referencing one-to-many

Some problem domains have an entity that must have one or more references to itself.

A classic example is an “Employee” class.

An Employee has a supervisor. (Let’s keep this example simple. Just one supervisor.)

However, if the Employee is a supervisor, then they will have a collection of Employee objects that they supervise.

assoc-self-one-to-many

.

Prerequisite topic – nullable types

When you define a value type property, it is mapped, by convention, to a “not null” column in a relational database table.

However, you can ‘allow nulls’, by using a nullable type in your design model class. How?

Define a value type (e.g. int, double) property as nullable in a design model class. Then, the SQL Server database engine will create its table column with the “allow nulls” checked/set to true.

Two syntax formats are available to you. For example, to define a nullable int, use either of these:

public int? Age { get; set; }

public Nullable<int> Age { get; set; }

When working with a nullable property (e.g. in manager, controller, or view code), a nullable type has a useful extension method that prevents ‘null reference’ exceptions:

GetValueOrDefault()

.

Working with the self-referencing one-to-many association

To create a self-referencing “to-one” property:

1. Add a nullable int to hold the identifier of the referenced object. For example:
public int? ReportsToEmployeeId { get; set; }

This is an Entity Framework Code First convention. It causes the relational database server to correctly configure the table and relationship.

2. Add a navigation property for the object. For example:
public Employee ReportsToEmployee { get; set; }

Then, we perform data operations by using the same technique you’ve used before, using the navigation properties. Do not use the nullable int property. 

View model classes: The “base” view model class includes both ‘to-one’ properties (the nullable int and the object itself). Then, create another view model class that includes a collection property for the collection. For example:

  • EmployeeBase – typical employee view model class, with the identifier, all or most properties, including (as noted above) both ‘to-one’ properties
  • EmployeeBaseWithEmployees – inherits from EmployeeBase, adds an ICollection<EmployeeBase> property; its name MUST match the design model class property name (e.g. “EmployeesSupervised”) for AutoMapper to do its job correctly

Manager: When fetching an object, use the Include() method if you want to include the associated object(s) in the fetch. You’ve done this before. If you want to include several associated objects, add several Include() methods. Make sure that the method’s return type is correct (e.g. IEnumerable<EmployeeBaseWithEmployees>).

AutoMapper: Define your maps as you have learned. No special steps are required. When the map is executed, the associated  object or collection will be correctly processed.

Study the SelfOneToMany web app code example on the GitHub code repository.

.

Association – one-to-one

Some problem domains need a one-to-one among entities.

An example, based on the one above, is where an employee has a home address, and/or a work address.

The address should be its own entity, because that’s a better design.

assoc-one-to-one

One end must be “principal”, the other end is “dependent”.

An Employee object – the Principal end – can exist without the object at the other end of the association. In other words, must (can) create the principal object first.

An Address object – the Dependent end – must be configured with its associated object when it’s created. In the design model class, the navigation property to the other end of the association (on which it depends) must have the “Required” attribute.

Coding and working with the associated objects is similar to what you’ve seen before.

Study the OneToOne web app code example on the GitHub code repository.

.

.

.

.

.

.

.

.

.

.

.

.

.

Advertisements
  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: