As its name suggest, with code-first, you start with the code. You can
create the corresponding database directly from the code, but you could
also be working from an existing DB. The advantage of code-first is
that your entity-classes don’t have any EF artefacts on them: they
don’t derive from a specific class and they do not have funky attributes
on them. Well… for the attributes, as we’ll see, that’s optional!
Let’s start with a simple entity model: Order and OrderDetail. We
start by modelling it as classes:
public class Order
{
public int
OrderID { get; set; }
public string OrderTitle { get; set; }
public string CustomerName { get; set; }
public DateTime TransactionDate { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
OrderDetailID { get; set; }
public int OrderID { get; set; }
public decimal Cost { get; set; }
public
string ItemName { get; set; }
public Order Order { get; set; }
Note the following about those classes:
- They do not derive from any EF classes
- They do not use EF attributes
-
An Order contains a list of OrderDetail and
an OrderDetail contains a reference to its Order
- Each property is either
-
- A simple CLR Type (e.g. string, int, etc.)
- An entity-type (e.g. Order)
- A list of entity type (e.g. List<OrderDetail>)
In order to map those class into a DB, we need a container, a
database-context:
public class MyDomainContext : DbContext
public DbSet<Order> Orders { get; set; }
DbSet<OrderDetail> OrderDetails { get; set; }
static MyDomainContext()
{
Database.SetInitializer<MyDomainContext>(new
DropCreateDatabaseIfModelChanges<MyDomainContext>());
}
This class is EF-aware. It doesn’t have to sit in the same assembly
than your model classes though.
At least a context must satisfy the following:
- It derives from System.Data.Entity.DbContext
- It has a property for each entity set we want to expose
-
Each property is of type System.Data.Entity.DbSet<T>
where T is the type of the entity
- Each property is read / write (get / set)
With that in place在这里, the DbContext base class uses reflection
to pick-up the entity-sets and a bunch of convention to infer the
underlying database model it should map to.
The conventions take decisions such as for the entity of type
Order, the property OrderID must be its primary key. Other
convention will infer the column-name (by default the property name),
the column type (e.g. a string maps to nvarchar(128) and should be
nvarchar(MAX) in the
final
version
), if a column is nullable (by default, all column but
primary and foreign keys are nullable), etc. . We’ll see that there
are ways to override those conventions.
We’ve added a static constructor here. The instruction in the static
constructor sets a standard for the entire app-domain: when a database
context is initialized, check if the schema in the database is conform
to the model and if not drop the DB and recreate it. The way this is
done is that EF creates a table dbo.EdmMetadata and persist a
hash of the model schema in it.
If the database doesn’t exist, EF will create it. Which database?
By default, it creates a DB with the name of your context on the local
machine. You can override that in many ways. The simplest is to add a
connection string in your configuration file with the name of the
context (in my case, "MyDomainContext"). Another way is to
implement a constructor and call the non-default base-class constructor
in it.
In the next blob entry, I’ll show how to override the conventions.