Thursday, May 26, 2011

Entity Framework Feature CTP4: DbContext & Databases

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.

Default Conventions

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.

Connection Factories

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);
}

Changing the Database Name

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; }
}

Changing the Database Server

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");
 
   ...

}

Changing to SQL Compact

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.

App.config/Web.config

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.

 
Read Complete Article from MSDN Blog..  really a nice article..
http://blogs.msdn.com/b/adonet/archive/2010/09/02/ef-feature-ctp4-dbcontext-and-databases.aspx
 

No comments :

Post a Comment