Recall that a model is the code used to interact with the data in your application. If you work with a database, this code typically returns a list of data or a single record. The code also supports user interaction on that data (create, update, and delete). If you already have a set of classes for working with your database and expressing your business logic, you can use them for your model. If you don’t have these classes, you need to create them.
As an example, imagine that you have a database that contains a Customers
table. You could write a custom class to express the properties and validation rules of a Customer
object. You might also write functionality to get a list of customers, read a single customer, update a customer in the database, and more. Alternatively, you can let the Entity Framework handle much of this work on your behalf. This saves you from writing the data access, update, storage, and delete code from scratch. In this example, we use the Entity Framework 7 Code First. (See Chapter 13 for more details on working with databases.)
With Code First, you write very little code, and you do not have a bunch of generated code in your solution. Instead, you write plain old CLR objects (POCOs) classes to represent your model. These classes define objects, properties, and business rules. The database access is taken care of for you with Entity Framework. The following walks you through building the Customer
model.
1. Start by creating a new project (File, New Project) based on the ASP.NET 5 Web Site template (or, if you’ve been following along, you can use the project you’ve already created for the other examples earlier in the chapter).
The examples assume your site is named, AspNet5AppSample
. This name is used in the namespace definitions for class files.
2. Inside Visual Studio Solution Explorer, right-click the Models
folder and choose Add, New Item. Select the Class template from the Add New Item dialog. Name the class Customer.cs
.
3. Create the properties to represent a simple Customer
instance. Listing 17.4 shows an example.
using System;
namespace AspNet5AppSample.Models
{
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public bool OptInEmail { get; set; }
public string Notes { get; set; }
}
}
ASP.NET includes support for data annotations. A data annotation is metadata that you assign to the properties of your class using data attributes. This metadata is then interpreted by ASP.NET at runtime as validation rules for the properties in your class. For example, you might annotate a property with the RequiredAttribute
. ASP.NET will then validate your model both on the client (using JavaScript) and on the server. If the model state is not valid, the object is not valid and the user should be notified.
The data attributes are found in the System.ComponentModel.DataAnnotations
namespace. There are dozens of attribute classes available to you. However, the following provides an overview of many of the common data attribute classes. (The word Attribute is omitted from the class name for clarity.)
Association
—Used to indicate the property works as a data relationship (or foreign key).
Compare
—Used to compare the values of two properties (such as password and password match).
CreditCard
—Used to indicate that a given property should be a credit card number.
DataType
—Used to mark a property as a specific data type. This is useful if the actual type you intend is different from the one stored in your database. For example, you may have a PostalCode
property you store as a string in the database but want to validate it as numeric.
Editable
—Used to indicate if a given property should be allowed to be changed by a user. You can use this attribute to mark a property read only or allow an initial value.
Email
—Validates a property as containing an email address.
Key
—Used to indicate if a property represents a primary key for the item.
MinLength
, MaxLength
—Used to validate against a min or max length of a property that represents a string or array.
Phone
—Validates a given property contains a valid phone number.
Range
—Used to validate against an allowable numeric range for the property.
RegularExpression
—Allows you to write a regular expression against which the property should be validated.
Required
—Used to mark a property as requiring a value.
StringLength
—Used to set the min and max length of characters in a property of type string
.
Url
—Validates a property as a URL.
The attribute classes just listed all work in a similar way. You use them to annotate properties of your object. A simple validation attribute will require no additional configuration and will include a default message to be displayed when the validation fails. However, some data annotation attributes require additional configuration to work properly, such as setting the maximumLength
on StringLength
. Each attribute also includes the ErrorMessage
property that allows you to set a custom error message if validation fails.
Let’s add a few data annotations to the Customer
class created previously. The following walks you through this process:
1. Add a using
statement at the top of Customer.cs
for System.ComponentModel.DataAnnotations
.
2. Annotate the Name
property with the Required
attribute.
3. Add both the Required
and the EmailAddress
to the Email
property. You can do so by separating them with a comma.
Configure the ErrorMessage
property for the EmailAddress
attribute to set a custom message to be displayed when the property is not valid.
4. Mark the Id
property with the Key
attribute to indicate this is the primary key for the object.
5. Constrain the Notes
property using StringLength
. Set the maximumLength
to 250.
Listing 17.5 shows an example of what your model should now look like following the addition of these data annotations.
using System;
using System.ComponentModel.DataAnnotations;
namespace AspNet5AppSample.Models
{
public class Customer
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required, EmailAddress(
ErrorMessage ="Please use email format, [email protected]")]
public string Email { get; set; }
public bool OptInEmail { get; set; }
[StringLength(maximumLength:250)]
public string Notes { get; set; }
}
}
ASP.NET will use these data annotations to execute validation on the client (using the jQuery.validate
plug-in). They will also be part of the model state validation on the server (inside your controller). You will see these in action later in the chapter as we round out this sample.
The next step with Entity Framework 7 (EF7) is to create a database context class that derives from Microsoft.Data.Entity.DbContext
. Entity Framework uses the database context class to get enough information about your objects so it can work with the entities in your database. You can do a lot with DbContext
and related Entity Framework code (including handling object to data entity migrations/updates). However, this example simply uses this approach for writing Customer
objects to a database.
Recall that EF7, like ASP.NET Core 5, is now modular. The project template in our sample already includes a reference to EF7 for SQL Server. You can open the project.json
file to see this ("EntityFramework.SqlServer": "7.0.0-beta4"
). You could replace this, for example, with SQLite using NuGet and installing EntityFramework.SQLite. For our example, however, we will stick to the SQL Server version. The following walks you through this process of creating the DbContext
object:
1. Add a class to the Models
folder called CustomerDbContext.cs
. To do so, right-click the Models
folder in Solution Explorer and choose Add, New Item. Select the Class template.
2. Add a using
statement at the top of the class for Microsoft.Data.Entity
.
3. Update the CustomerDbContext
class definition to inherit from DbContext
.
4. Create a public property of type DbSet<Customer>
called Customers
.
Listing 17.6 shows the new CustomerDbContext
class.
using System;
using Microsoft.Data.Entity;
namespace AspNet5AppSample.Models
{
public class CustomerDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
}
}
Of course, we need a database with which to work. EF7 supports working with an existing database or using the tools to create one based on your model. In past versions of the Entity Framework, you could simply run your application; if EF did not find the database, it automatically created one for you. However, this database generation at project runtime was problematic and difficult to keep in synch beyond the initial database generation. EF7 addresses these issues. You no longer get a database just by running some code. Instead, you can use console commands to generate a database migration script based on your model. You can then execute that script to create your database. These migration scripts are code files stored in the Migrations
folder of an ASP.NET MVC project. You can use these files to keep your database and model in sync during development and deployments.
To get started, we will define a connection string for working with the database. There are many places we can put the database connection. For this example, we will use the config.json
file for storing a database connection string for our project. The following walks you through the process:
1. Open the config.json
file from Solution Explorer. Notice there is already a Data
group with a DefaultConnection
item. This was created by the template for working with the ASP.NET user profile and membership services.
In the example, however, we plan to store membership data and application data in the same database. Therefore, edit the connection in the file to point at a new database named AspNet5Unleashed
. (Database=AspNet5Unleashed
). We will generate this database in a moment.
Note that you may also have to change your server name in the connection string depending on your installation. To get your server name, open SQL Server Object Explorer in Visual Studio (View, SQL Server Object Explorer). Your local database server should show in the tree (along with its name).
You can also right-click the server and choose Properties. Here you can find the “Connection string” property to use as a guide. For example, you can use the first section, Data Source=(localdb)\ProjectsV12
; to get the server name, (localdb)\ProjectsV12
and update the default connection string to Server=(localdb)\ProjectsV12;
.
When complete, your connection string should look similar to the one shown at the top of Figure 17.20.
2. Now open Startup.cs
from Solution Explorer. Recall that this is where you configure the ASP.NET request pipeline. Navigate to the ConfigureServices
method.
You should see a call to services.AddEntityFramework()
. There are methods on this object that use dependency injection to add additional dependent services at runtime. Use this call to add registration for the CustomerDbContext
instance as shown here.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration
["Data:DefaultConnection:ConnectionString"]))
.AddDbContext<CustomerDbContext>(options =>
options.UseSqlServer(Configuration
["Data:DefaultConnection:ConnectionString"]));
Now that you have defined a connection to the database, you need to actually create the database. You can do so manually using SQL Server Object Explorer. You can also use the EF7 migration commands in Visual Studio to generate your database from your model. You will see an example of both scenarios. Some developers like to use the SQL tools and create the database manually. Others prefer to keep their database in synch with their models using tools.
Let’s start by looking at how you would automate database schema updates using EF migration. To do so, you will use commands that are part of the EntityFramework.Commands
package installed by the default template. You can see this package in the References
folder in Solution Explorer and in project.json
. In the latter, these commands get mapped to the ef
variable. You will use this in the command window to generate a migration file and execute it.
The Commands
package makes working with data migrations (object to entity mapping) easier. However, this NuGet package is optional; you do not need to use it. In addition, there is no need to deploy it once you are done doing development. Instead, you can set the package as a dev-time dependency.
Visual Studio also includes tools called the DNVM (.NET Version Manager) and DNU (.NET Development Utility). These are command-line tools that uses the EntityFramework.Commands
package to help you generate code for a migration based on your model. The following walks you through creating the database from your models using commands from these tools:
The EF7 code was in beta (beta 4) at the time of writing. In addition, the supporting tools were also in development. This section walks you through what was available at the time of writing: the command line approach to creating and applying a migration based on your model. However, it is possible the tooling will also be integrated directly into the Visual Studio IDE. That said, this command line approach should still operate as outlined.
1. Open the Developer Command Prompt for VS2015 (Windows Start, Developer Command Prompt for VS 2015). This opens a command window setup to work with Visual Studio command line tools.
2. To get started, you need to change the active directory in the command prompt to folder that contains your project.json
file. In our example, you use the cd command to navigate to the project folder. You then use the following to get to the folder containing project.json
:
cd .srcaspnet5appSample
3. Next, you need to use DNVM to add a .NET runtime for use by the command window. You can do so using the use
command. To see a list of available runtimes, type dnvm list
. To bind a runtime to the path, use the following command at the prompt (where your version number matches that found in the dnvm list
):
dnvm use 1.0.0-beta4 coreclr
4. You may also have to use the DNU to restore NuGet packages before continuing. You can do so using the following command:
dnu restore
5. You are now ready to execute a command to create an EF7 migration. You do so using the DNX tool and the ef
command. The ef
command is defined inside project.json
under Commands to point to EntityFramework.Commands
.
The first step is to generate migration code based on your data context object. The following command does so. You can see that we name the migration InitialSchema
; the migration class will contain this name. We also explicitly indicate which class (CustomerDbContext
) we want to use as a basis for the generated migration code (as there may be more than one in your project).
dnx . ef migration add InitialSchema -c CustomerDbContext
6. Upon success, return to Visual Studio and navigate to the Migrations
folder for your project. You should now have two new files in the folder: one that ends with the name, _InitialSchema.cs;
and another with the name, CustomerDbContextModelSnapshot.cs
.
7. The DNX tool will use these classes to apply this migration to your database. The database connection will be gleaned from your project file, config.json
. Enter the following apply
command inside the command window.
dnx . ef migration apply -c CustomerDbContext
You can now return to Visual Studio and open the database (View, SQL Server Object Explorer). You may have to use the refresh button on the tool pane window. You should then see the AspNet5Unleashed database and the dbo.Customer
table.
This EF7 migration method can be used to keep your model and database in synch. As you make changes to the model, you can use the commands discussed here to create migration scripts. You can then apply these scripts as required to various environments in order to deploy your database changes.
Some developers prefer to create the database manually using script or the tools themselves to generate script. Visual Studio and EF7 support this scenario. The following walks you through creating the database manually using Visual Studio:
1. Open SQL Server Object Explorer from the View menu; navigate to your database and the Databases
folder.
Right-click the Databases
folder and choose Add New Database. Name the database AspNet5Unleashed
.
2. Expand the node that represents your newly created database. Navigate to the Tables
folder and right-click it. Select Add New Table.
3. Use the table designer to create fields for the Customers
table. Use the T-SQL script editor to change the name of the table to Customer
(singular).
Figure 17.21 shows an example of what your table should look like.
4. Right-click the Id
property and choose Properties. Set this primary key as an Identity
column with an Identity Seed of 1 and an Identity Increment of 1. See the right side of Figure 17.21 as an example.
5. Click the Update button on the table designer to update the database. This brings up the Preview Database Updates dialog. If all looks right, click the Update Database button to submit your changes. You should see the changes as they are being made inside the Data Tools Operations window. Note that Visual Studio will ask you if you want to save the .sql
script file. This is not necessary for most workflows as you can always regenerate this if necessary.
You should now have a database, a data context class, and a class that represents your data model. Entity Framework should also now be configured to connect to and work with your database. The next step is to write a controller for handling requests for customer data and views.