BTI420 notes – Wed Jan 15

Collections. Data relations/associations. Session state persistence. LINQ (language-integrated query). Get data from a user.

.

Busy day today. Lots of topics. Lots of code examples in the GitHub repository’s “Week_02” folder.

.

Collections

It’s time to learn about collections.

When we work with data in our web apps, we are going to do lots of work with objects, and collections of objects.

The following is from the MSDN Library Collections and Data Structures document:

Closely related data can be handled more efficiently when grouped together into a collection. Instead of writing separate code to handle each individual object, you can use the same code to process all the elements of a collection.

To manage a collection, you can … add, remove, and modify either individual elements or a range of elements in the collection.

Here’s some more information, from the MSDN Library:

Commonly Used Collection Types (we will use ICollection<T>, List<T>, and IEnumerable<T>)

When To Use Generic Collections

Introduction to Generics (first paragraph only)

List<T> Class reference

A collection can be created and used anywhere in your code. We also see collections as properties in data classes. When we declare a collection property in a data class, we often use the data type ICollection<T>. The T is a type name placeholder, which will be replaced by the actual collection type (e.g. Person, Vehicle, Product, etc.).

Reference information is described in the ICollection<T> document. (To search for this yourself, use this search engine term: msdn library icollection<t> interface) The “Remarks” and “Examples” sections of that document will help you learn.

When you add a property of type ICollection<T>, you MUST do one other task: In the default constructor, initialize the property by using a concrete type.

ICollection<T> is an interface. You can tell, because .NET Framework interfaces have an upper-case letter “I” prefix. In C++ programming, you learned about an abstract class with pure virtual methods. In C# and the .NET Framework, the counterpart is an interface.

best practice tells us to use an interface as the data type when declaring properties in a class. However, just as in C++, we cannot initialize an interface. Instead, we must use a concrete type that implements/inherits the interface. (Why don’t we just declare the property’s data type as the concrete type? Well, it’s not a best practice. You’ll understand more later.)

So, in a data class that has a collection property (probably named “Products”, of data type “Product”), we write the following code in the default constructor:

this.Products = new List<Product>();

.

Data relations/associations

We will discuss, study, and code some typical relations, or associations, between entities. Examples we’ll use:

  • Supplier – Product
  • (from the School of ICT…) academic Program – Subject
  • vehicle Manufacturer – Vehicle

.

Kinds of associations

Real-life and software objects can have associations between them. When writing data classes, the associations are simply coded as properties. However, they’re often called “navigation properties“.

There are several kinds of associations that you could code:

  • one to many (this is the one we’ll study first, because it’s simple and easy to understand)
  • many to many
  • one to one
  • to one, self-associated
  • to many, self-associated

.

Declaring a navigation property

When writing associated classes, ALWAYS add a navigation property to both associated classes.

Declare a to-one property with the data type of the associated class. For example if a Product is sold by a single Supplier:
public Supplier Supplier { get; set; }

Declare a to-many property with a collection type of the associated class. For example, a Supplier sells a number of Product items:
public ICollection<Product> Products { get; set; }

(Remember, whenever you declare a collection property, you MUST initialize it in a default constructor.)

.

Setting the value of a navigation property

Before setting the value of a navigation property, you must have a reference to an object (of that data type). Although you can create a new object in the statement, you will often have another existing variable for (or reference to) the object.

Set a to-one property as follows. Assume that ‘walmart’ is a Supplier object, and ‘shirt’ is a Product object:
shirt.Supplier = walmart;

Setting a to-many property requires some thought. Do you want to add a new object to the collection? Do you want to replace the existing collection with a new collection? Here are some examples, using the same ‘walmart’ and ‘shirt’ objects, but we also have a collection of toaster objects named ‘toasters’:
walmart.Products.Add(shirt); // add a new object to the collection
walmart.Products = toasters; // replace the existing collection with a new collection

Important: When you write a statement in code to set one end of the association, do you need to write another statement to set the other end? It depends:

  • During the first few weeks, when we use in-memory objects, YES, we must set both ends of the association.
  • Later in the course, when we use a persistent store (SQL Server via the Entity Framework), NO, we don’t have to. In this scenario, when you set one end of the association, the persistence framework sets both ends of the association.

.

Getting the value of a navigation property

Getting the value of a navigation property is natural and simple. Just pay attention to data types (an object, or a collection of objects).

Also, when you have a to-one association, it’s easy to ‘walk’ the object graph to get access to properties in the associated object. For example, using the ‘shirt’ object from above, you could get the “Name” or “Address” of the supplier:
string supplierName = shirt.Supplier.Name;

.

Session state persistence

Session State is a storage area in the memory space of a web app. It is organized as a dictionary-like collection that can hold one or more items. Each item has a string key identifier, and its value can be an object of any type.

When a browser user/client accesses a resource in your web app for the first time, the ASP.NET runtime creates a “session”, which is simply a logical grouping of requests from the same browser window/tab during a limited time window.

As suggested above, the lifetime of an object in Session State is limited. By default, it’s twenty minutes. (Therefore, if more than twenty minutes elapses between requests, the old session object expires, and a new one created.)

This MSDN Library document is an overview of Session State.

The syntax for reading from, and writing to, Session State is shown below. “Session” is the programmatic property name.

Assume that you wished to store a string, and a collection, in Session State. Here’s how:

Session[“greeting”] = “Hello, world!”;
Session[“products”] = purchasedProducts;
// assuming that purchasedProducts is a List<Product>

Now, assume that you wished to fetch a string, and a collection, from Session State.

First, check whether the value is still in Session State:

if (Session[“whatever”] != null) …

You must cast or convert the object reference to the desired type. Here’s how:

greeting = Session[“greeting”] as string;
// assuming that result is a string variable
purchasedProducts = Session[“products”] as List<string>;
// assuming that userSelections is a List<string>

.

LINQ (language-integrated query)

LINQ – language-integrated query – is a C# language feature that supports in-language operations on data.

The operations include the full range of query, add, change, and remove. The data store can include a wide range of possibilities, from in-memory object collections, the file system, a relational database, and a remote/web service/cloud store.

When you use LINQ, you can use either one of two syntax forms:

  • query expression
  • fluent

.

“Query expression” syntax

For those familiar with relational database querying, the LINQ query expression syntax will appear familiar. A typical query expression consists of these parts:

from …
where …
orderby …
select …

So, a typical query expression looks like this:

linq_query_expression

.

In the “from” clause, “m” is known as a local range variable, which represents the items in the data source during the query. A local range variable can be one character, or it can be two or more characters.

.

“Fluent” syntax

Fluent syntax uses methods, and method chains, to do the work. The example from above would look like this:

linq_fluent

.

For readability, we can also use multiple lines, if you split before the dot:

linq_fluent_split

.

Note that many of the methods require a code expression; a function. The function could extract, filter, or project – the developer decides its behaviour.

The function syntax is known as a lambda expression in C#. (It is often referred to as an inline method. More generically, it is known as an anonymous function.) The syntax below shows a lambda expression that returns an entity object that matches a specific condition:

c => c.CustomerID == 23

The return type is inferred from the context in which it is used. In other words, if the lambda expression is used as an argument to a LINQ statement that is supposed to return an entity object, then the return type of the lambda expression above is the entity object type.

Anonymous functions can “see” the local variables in the surrounding methods. Repeating the example syntax above, assume that the method that surrounds the lambda expression includes a local variable named “custID”, and the variable held the value “23”. The new syntax would be:

c => c.CustomerID == custID

Note that if there is already a local variable named “c” in the surrounding methods, you must use a different local range variable.

How do you read or pronounce this syntax? As suggested by Hejlsberg and others (see this StackOverflow article), it can be read as any one of the following:

such that c.CustomerID is equal to custID

becomes (the result of) c.CustomerID equals custID

for which c.CustomerID is equal to custID

maps to c.CustomerID equals custID

lambda of c.CustomerID is equal to custID

.

For more examples, study the “Getting started…” section of the LINQ article by Hejlsberg and Box (linked below).

To get started learning about LINQ, study this document: LINQ: .NET Language Integrated Query, by Anders Hejlsberg and Don Box

Be sure to read at least these sections:

  • .NET Language-Integrated Query
  • Getting Started with Standard Query Operators
  • Lambda Expressions and Expression Trees

.

Get data from a user

There are many ways to get data from a user into your app. Today, we will study three ways:

  1. From the URI, as query string data
  2. From an HTML Form, by reading the values in the request body data
  3. From an HTML Form, by using the preferred way, which is to use a strongly-typed view model

.

From the URI

The request processing framework parses ALL query string key-value pairs.

However, you can add parameters to the controller method for important values:

  • The parameter name must be used as the key name on the query string
  • The parameter data type must be string

Adding a parameter makes it simpler to refer to its passed-in value. If you don’t add the parameter, you’ll have to enumerate through all key-value pairs, looking for the data you need or want.

You must check whether the passed-in value exists. There are at least two ways to do this:

  1. Check whether Request.QueryString[“whatever”] is null or not
  2. Use string.IsNullOrEmpty(parameterName)

.

From an HTML Form, request body data

We ALWAYS use two methods with an HTML Form.

  • One method displays the form
  • The other method handles the form’s posted data

A programming best practice tells us to prefix the form post handling method with an [HttpPost] attribute.

In the form post handling method, your code can access the HTML Form data by using Request.Form. For example, assume that you wish to get access to the “first name” text box data (<input name=”firstName”…):

string firstName = Request.Form[“firstName”];

The data type of all incoming data is string. You must cast/convert to other data types if you need to.

After the form post handler completes its work, it ALWAYS redirects to a page/view. It can be to the same page, or to some other page. This approach implements the Post/Redirect/Get (PRG) pattern:

  1. Post: The page user submits the form, which creates an HTTP POST request
  2. Redirect: The form post handler completes its work, then 1) sets the Location response header to the URI of the page to go to, and 2) sets the response status code to 302
  3. Get: The browser receives the response, and as a result of the status code 302, it sends another HTTP GET request to the URI of the page that was in the Location header

.

From an HTML Form, strongly-typed view model

As noted above, we ALWAYS use two methods with an HTML Form. And we ALWAYS use the PRG pattern.

What’s different in this approach? Well, Request.Form works fine for a few input fields, but an HTML Form with many inputs requires more code. In addition, there’s no check or test whether data for all fields was submitted. (And no check for “over-posting”, which is a security threat.)

Here’s what to do. It’s simple. Add a parameter to the form post handling method; its data type is a view model which matches the exact shape of the data collected in the HTML Form.

Then, at the top of the method, you can add this simple test:
if (ModelState.IsValid) …

The request processing framework will match and validate the posted data against the view model. (Soon, you will learn about data annotations, which enhance this match-and-validate process.)

Your code will also be easier to write, with fewer statements. Compare the two ways of getting access to a ‘first name’ HTML Form value. The first statement uses Request.Form, and the second uses the local variable name for the passed-in strongly-typed object (perhaps named “newperson”):

string firstName = Request.Form[“firstName”];
– or –
string firstName = newperson.FirstName;

.

.

.

.

.

.

.

.

.

.

.

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: