This post is largely targeted at using the Code First approach with DbContext
to generate a
database, if you are mapping to an existing database then this
is covered at the end of the post.
First let’s look at the default behavior of DbContext and how it uses
convention rather than
configuration to reduce the amount of code we need to
write to get an application up and
running. Below is a complete application
that uses DbContext to persist and query data
using DbContext. No additional
code or configuration is required; DbContext will automatically
create a
database for us based on our domain model. The database will be created on our
localhost\SQLEXPRESS instance and will be named after the fully qualified
type name of
our derived context (in the following example this would be
PI.DbDemo.ProductCatalog).
using System;
using System.Collections.Generic;
using System.Data.Entity;namespace PI.DbDemo
{
class Program
{
static void Main(string[] args)
{
using (var context = new ProductCatalog())
{
// Persist Data
var food = new Category { Name = "Food" };
context.Categories.Add(food);
context.SaveChanges();// Query Data
foreach (var cat in context.Categories)
{
System.Console.WriteLine(cat.Name);
}
}Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}public class ProductCatalog : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }public ICollection Products { get; set; }
}public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal UnitPrice { get; set; }public Category Category { get; set; }
}
}
Of course this convention is useful to get up and running but it’s not going
to get us all the
way to deploying in a production environment, you probably
aren’t going to be using a local
SQL Express instance in production and if
you’re an enterprise developer your DBA probably
isn’t going to overjoyed at
the idea of you application having permissions to create databases
(with
good reason). In the next sections we’ll look at how you can start to take
control over
the database as your requirements progress.
Under the covers there is a convention that is taking the name of your
context and turning it
into a database connection, this is an AppDomain wide
setting that can be changed via a
static property;
System.Data.Entity.Infrastructure.Database.DefaultConnectionFactory.
Connection factories implement the
System.Data.Entity.Infrastructure.IDbConnectionFactory
interface which
defines a single CreateConnection method. When you use the default
constructor on DbContext the fully qualified name of your context is passed
to the default
connection factory to obtain a database connection.
public interface IDbConnectionFactory
{
DbConnection CreateConnection(string nameOrConnectionString);
}
If you just want to change the name of the database that is generated then
you can control
the string that is passed to the default connection factory
by using the DbContext constructor
that specifies the nameOrConnectionString
parameter. Here is our derived context updated to
specify a database
name:
public class ProductCatalog : DbContext
{
public ProductCatalog()
:base("DemoProductStore")
{ }public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
If you want to have your database on another Microsoft SQL Server Instance
then you can
tweak the settings on the SQL Client connection factory that is
included in CTP4;
System.Data.Entity.Infrastructure.SqlConnectionFactory.
This connection factory includes
a constructor that allows us to override
pieces of the final connection sting, such as
username, password and server.
We need to make changes to the default convention before
any contexts are
created in our AppDomain, in the case of our console application we can
just
do this at the start of the Main method:
static void Main(string[] args)
{
Database.DefaultConnectionFactory =
new SqlConnectionFactory("Server=MyDatabaseServer");
...}
Along with the SQL Client connection factory we also include the
System.Data.Entity.Infrastructure.SqlCeConnectionFactory which will generate
connections to
SQL Compact databases. Because the SQL Compact providers
aren’t backwards compatible
you will need to specify the invariant name of
the provider version you want to use. Currently
the SQL Compact 4.0 provider
is the only one that supports Code First database creation
and it is
available for download
as a separate CTP.
static void Main(string[] args)
{
Database.DefaultConnectionFactory =
new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");...
}
By default SQL Compact files will be created in the |DataDirectory|
directory, for executables this
is the same directory as the executable, for
web applications this is the ‘App_Data’ directory.
The SQL Compact factory
also includes constructors to override the directory that databases are
created in, or any other part of the connection string.
All these conventions are great but if our database server changes between
dev, test and production
then we really want to be able to change it easily
without having to recompile code. No problem, just
add a connection string
to your applications config file with a name that matches the name of your
context (either fully-qualified or not). Because the shape of the model
comes from your code rather
than xml files this is just a plain connection
string rather than an EntityClient connection string used
in other areas of
EF.
<configuration>
<connectionStrings>
<add name ="ProductCatalog"
providerName="System.Data.SqlClient"
connectionString="Server=.\SQLEXPRESS;Database=ProductCatalog;
Integrated Security=True" />
</connectionStrings>
</configuration>
Note that if you pass a string to a DbContext constructor (for the
nameOrConnectionString parameter)
then that string should match the name of
the connection string added to your config file.