Thanks for visiting my blog!
NOTE: This post has been updated for changes in Beta 7 and later.
Every web project needs some sort of data framework and ASP.NET 5 is no exception. Like it’s forbearers, ASP.NET 5 uses Entity Framework, but this version of the Entity Framework is different. It’s being re-engineered from the ground up just like the ASP.NET 5 stack.
In this, the third part of my ASP.NET 5 series, I’ll be talking about Entity Framework 7. While you can use older versions of EF or other storage mechanisms (NoSQL, Postgres, etc.), I think it’s an interesting exercise to see what the EF team is thinking in this evolving version of the framework.
I’ll explain what I’m doing in a series of blog posts and link them all here as I write them. The plan is to write posts about:
Part 3: Using Entity Framework 7 (this post)
Part 6: Web Tooling with VS2015 (coming soon)
The project will continue to evolve and you can always get the latest version by visiting it on GitHub:
First thing to understand is that EF7 isn’t done. It’s a work in progress. So much of the warts and pain points I discuss here will hopefully be gone by the time you’re actually using the framework in ASP.NET 5 projects.
Configuring Entity Framework
To get started with Entity Framework 7, you need the reference. By default this is already there but for when you need to update to new versions, I thought I’d point it out where it is in the project.json file:
{
/* Click to learn more about project.json http://go.microsoft.com/fwlink/?LinkID=517074 */
"webroot": "wwwroot",
"version": "1.0.0-*",
"dependencies": {
"EntityFramework.SqlServer": "7.0.0-beta7",
"EntityFramework.Commands": "7.0.0-beta7",
"Microsoft.AspNet.Mvc": "6.0.0-beta7",
```csharp
If you remember the last post, the **startup.cs **allowed for configuration to happen in two phases<font color="#333333">. First the configuration of the different elements, then the registering of services with the dependency injection layer. So let’s start there.</font>
<font color="#333333">The service container is the dependency injection mechanism built into ASP.NET 5 and the <strong>ConfigureServices</strong> method is where that happens. Before we can add EF to the DI container, we need to get a connection string. </font>
<font color="#333333">When I first came to ASP.NET 5, it looked as if the EF configuration would just load the connection string by convention, but it didn’t work. So I had to get it manually and add it (below) when I configured the context object. So, instead, I just grabbed it from the <strong>Configuration </strong>object that was created in the constructor:</font>
```csharp
// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.Get("Data:DefaultConnection:ConnectionString");
```csharp
The **Configuration.Get **method allows it to read a setting from the list of configuration
<font color="#333333">sources. If you remember from the last post, the <strong>Configuration </strong>object is a merge of the <strong>config.json </strong>file and any environment variables. In the case of the connection string, we’re looking for a string called “<em>ConnectionString</em>” inside an object graph. This should look obvious once you see the <strong>config.json </strong>file:</font>
```js
{
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\MSSQLLocalDB;..."
}
},
"EntityFramework": {
"ApplicationDbContext": {
"ConnectionStringKey": "Data:DefaultConnection:ConnectionString"
}
}
}
So now that we have the connection string, what is next?
Next, Entity Framework is added to the services collection by adding it like so:
// Add EF services to the services container.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<MyCountriesContext>(options =>
{
options.UseSqlServer(connectionString);
});
```csharp
The **AddEntityFramework** method adds EF to the dependency injection container so it can be served if needed later. Additionally, calling **AddSqlServer** specifies the data store you’ll be using. Finally, the **AddDbContext** adds a **DbContext **object to the EF service (we’ll get to what that looks like below). The options lambda allows us to specify the connection string. I suspect this extra step will go away at some point and just read from the configuration by convention, but at this point it’s necessary. At this point, if we need the context in another part of the system (e.g. Controllers) we can just let ASP.NET 5 serve it to us in the constructor like any other dependency injection framework.
### Creating the DbContext
Assuming you’re somewhat familiar with Entity Framework, you should already know that the **DbContext** class has the responsibility of exposing the data in a data store via the Code-First semantics. Creating a **DbContext** derived class hasn’t changed substantially.
```csharp
public class MyCountriesContext : IdentityDbContext<ApplicationUser>
{
public MyCountriesContext()
{
Database.EnsureCreated();
}
public DbSet<Visit> Visits { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Visit>().Key(v => v.Id);
base.OnModelCreating(builder);
}
}
```csharp
The Database.EnsureCreated is important because it causes the database to be created and migrations to be run to make sure the database is up to date as well.
But this isn’t quite what I did. Originally, the project template created a context for the ASP.NET Identity system that derived from **IdentityContext**. but I didn’t want to have two disconnected **DbContext** classes. Instead of creating a new context like this, I just combined the two so that one context would be responsible for Identity and my own data (e.g. the Visits **DbSet**). I did this by deriving my context from **IdentityContext** as shown here:
```csharp
public class MyCountriesContext : IdentityDbContext<ApplicationUser>
{
public MyCountriesContext()
{
}
public DbSet<Visit> Visits { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Visit>().Key(v => v.Id);
base.OnModelCreating(builder);
}
}
Because I’m using this as my ASP.NET Identity context too, the configuration (in the **ConfigureServices **method of startup.cs) needs this context added too:
// Add Identity services to the services container.
services.AddIdentity<ApplicationUser, IdentityRole>(Configuration)
.AddEntityFrameworkStores<MyCountriesContext>();
Because I created a repository class that does the real work of the site, I’ll need to configure that in the ConfigureService method too. In this case, it’s a simple adding of the interface and implementation class like any other dependency injection framework you’ve used before (i.e. Ninject, Unity, etc.):
// Add other services
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
So that when I have a class that requires the IMyCountriesRepository, it passed in an instance of the MyCountriesRepository class as you’d expect. And since it is handling the dependency chains, it will fulfill any requirements that the repository class have (e.g. will pass in a created MyCountriesContext to the repository as that is a dependency of that class).
This implies something that is important:
If you’re not using dependency injection yet, get used to it…you’ll be doing it in ASP.NET 5!
Database Initialization in EF7 Today
In the creation of the DbContext, we saw that the code is calling Database.EnsureCreated() to cause the database to be created. What isn’t obvious here is that it also calls Migrations. Migrations are used to build the schema of your entities. But we need the migration to exist. Because I started this project back in an early beta, I’ve had to delete the entire set of migrations (the code in the Migrations folder) and rebuild the migrations a few times. Once we reach release, this won’t be as much of an issue.
To make the migrations, simply open up a console and type:
dnx ef migrations add {Name of Migration}
- or -
dnx ef migrations add InitialDatabase
```csharp
You’ll see these migrations show up in the project once you do that.
For seeding we have another problem. If you’ve done Entity Framework code before, you might be using the **DbInitializer** pattern to create the database and seed it. I am not sure if this part of EF7 isn’t done or whether they decided to just give you more control over the process, but in either case I needed a way to initialize the database creation and seeded data. Let’s see how I accomplished it.
The **DbContext **class I created looks different from the original one that the template project created. That’s because originally there was a hack in the code to allow you to create the database if necessary. I didn’t like how this worked so I broke out it into it’s own code.
I created a class called **SampleData** that is used to create the database and seed it if necessary. I created it as a static class, but you can do it whatever way you want. I started with a static method called **InitializeData**:
```csharp
public class SampleDataInitializer
{
private MyCountriesContext _ctx;
private UserManager<ApplicationUser> _userManager;
public SampleDataInitializer(MyCountriesContext ctx, UserManager<ApplicationUser> userManager)
{
_ctx = ctx;
_userManager = userManager;
}
Like any other class, I am simply going to use dependency injection to include the required objects for my sample data (I’m creating data in my context and creating sample users in ASP.NET Identity).
The real magic here is in a method called InitializeDataAsync:
public async Task InitializeDataAsync()
{
await CreateUsersAsync();
CreateVisits();
}
What is happening here is that I’m creating the users and visits. You’ll see later in the article why the CreateUsers needs to be async, but first creating the new visits is easy:
private void CreateVisits()
{
if (!_ctx.Visits.Any())
{
_ctx.Visits.Add(new Visit()
{
Id = 0,
UserName = "shawnwildermuth",
Country = "France",
City = "Paris",
VisitDate = new DateTime(2014, 6, 4),
Duration = 31,
Notes = "Start of our round-the-world trip",
ForWork = false,
ForFun = true
});
// ...
_ctx.SaveChanges();
}
}
```csharp
To start, I just see if any visits exist, if and if not, I create the visits. This code is just vanilla Entity Framework code (e.g. create objects, add them to the context, then save.
For the users in the system, I can’t just create the entities as there are rules in the Identity system. here I have to let **UserManager **do all the work:
```csharp
private async Task CreateUsersAsync()
{
var user = await _userManager.FindByEmailAsync("shawnwildermuth");
if (user == null)
{
user = new ApplicationUser { UserName = "shawnwildermuth", Email = "shawn@foo.com" };
await _userManager.CreateAsync(user, "P@ssw0rd!");
await _userManager.AddClaimAsync(user, new Claim("ManageStore", "Allowed"));
}
}
```csharp
Because the calls to **CreateAsync** and **AddClaimAsync** requires me to use **async**, the method also has to be async.
So now that I have the **SampleDataInitializer** class, how do I call it. For me, I just called it in the startup.cs. (A bit brute force? Sure.) But the challenge was how to create an instance of the **SampleDataInitializer** using the dependency injection system to fulfill my dependencies?
The trick is to use the ConfigureServices dependency registration. You can simple add it via **AddTransient** so that it’s created when you need it (and we’ll only need it once when the server is started):
```csharp
// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
// ...
// Add other services
services.AddTransient<SampleDataInitializer>();
Once that is registered, I can just use parameter injection to add it to the configure method (note the new SampleDataInitializer parameter):
public async void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerfactory,
SampleDataInitializer sampleData)
{
// ...
```csharp
<font color="#555555">Note that I changed the Configure to decorate it with <strong>async </strong>since our call to <strong>InitializeDataAsync </strong>requires <strong>async/await</strong>. Now we can just use the initializer to initialize the data like so (somewhere in the Configure, I do it as the last step:</font>
```csharp
// Configure is called after ConfigureServices is called.
public async void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerfactory,
SampleDataInitializer sampleData)
{
// ...
// Add Sample Data
await sampleData.InitializeDataAsync();
}
Now that database is being created and seeding, we can actually use the entities.
Using LINQ
The Entity Framework code inside of my project is no different than older EF projects:
public class MyCountriesRepository : IMyCountriesRepository
{
private MyCountriesContext _context;
public MyCountriesRepository(MyCountriesContext context)
{
_context = context;
}
public async Task<IEnumerable<Visit>> GetLatestVisits(int number)
{
return await _context.Visits
.OrderByDescending(v => v.VisitDate)
.Take(number)
.ToListAsync();
}
// ...
```csharp
<font color="#333333">So that once all this configuration and setup is done, you should be able to use it in the ways you’re used to. But there is one big caveat here: </font>
> <font color="#333333">Entity Framework 7 isn’t released yet so that lazy loading aren’t supported yet (as of the writing of this post) so you’ll need to use LINQ to load these manually. It’s a pain, but it works.</font>
<font color="#333333">Next time, I’ll dive into the meat of ASP.NET MVC!</font>