Archive

Posts Tagged ‘Feature CTP’

Code First with the Entity Framework 4.0 (CTP 4)

September 24, 2010 7 comments

Since the next CTP of the new Entity Framework 4.0 is available, containing many new features, I will present a little guide on how to get started with the Code-First programming model. This means we will define a pure domain model and use it to let EF create our database schema. I do like the idea of developing my model in code and then utilize a db shaped for that model. Of course this can’t be always achieved, but I tend to work towards it.

First things first: You will need to install the EF 4.0 CTP 4. You can download it from here.

1. Setting the demo context

We will be modeling a simple scenario from the real estate sector using properties, their adresses and agents who are selling the properties. Pretty simple, huh?!

2. The sample code

Open the Sample Solution (download is located at the end of the post) called IDevign.EF4. In there are two projects. The first one is called IDevign.EF4.Core and holds everything related to the Entity Framework like configuration, mapping and all loading/saving procedures. The second project is called IDevign.EF4.Domain. In here you will find the domain model which will then be persisted to the database. The following Class Diagram shows the entities we’re going to create:

 

EF4 Sample Class Diagramm

IDevign.Domain Class Diagramm

 

As I said before this model is pretty trivial so we can concentrate on the real topic: the EF 4.0. Now focus on the entites. These are all simple classes containing only a few properties. Just to clarify: as these classes are entities you are encouraged to put some domain logic (methods / behaviour) into them, although this sample has no need for that.

3. Creating the Domain Model

The first class we are looking at is RealEstateProperty (Property is not technical in this case):

public class RealEstateProperty
{
   public int Id { get; set; }
   public Agent ContractedBy { get; set; }
   public Address PropertyAddress { get; set; }
   public ICollection
 Buyers { get; set; }
}

Note that the Id Property will be taken as the Primary Key for this entity when using the Feature CTP 4 (see my previous post on EF 4 Conventions here). You don’t have to specify this explicitly like with the plain EF 4. The other point of interest is the ICollection of PotentialBuyer which stores people who are interested in buying this property. This results into an Foreign Key Relation from PotentialBuyer to RealEstateProperty which stores this information on each PotentialBuyer’s property interest. Also the addresses are entities by themselves. Again, this is not a full-scale domain model design regarding adresses as entities and not complex types (sql server feature), etc.

public class Address
{
   public int Id { get; set; }
   public string Street { get; set; }
   public string StreetNo { get; set; }
   public string City { get; set; }
   public string Zip { get; set; }
}

Nothing special in here. But to spice things up a little I created a little inheritance part inside this demo. There are two kinds of persons: Agents and PotentialBuyers. Agents show and sell properties to PotentialBuyers. Both types inherit from Person. All Persons have a name therefore the fullname goes into the base class. The specific parts are in the two specialized classes. But how does this whole thing work?

3.1 Inheritance Strategies:

There are three different strategies how inheritance can be handled inside of an relational database. Without going into details on these strategies here is a little wrap-up:

  • Table Per Type (TPT) – This means there will be one table in the database for every type you map. In our case this would be three tables. One for PotentialBuyer, one for Agent and one for the base type Person.
  • Table Per Hierarchy (TPH) – This is what we are doing here. There will be one table for all sorts of persons named People. It contains the data for Agents and PotentialBuyers. To differentiate between the two types an additional column is needed. This is a Discriminator column specifying the concrete type for each row. I will show you later how class hierarchies can be mapped using a discriminator.
  • Table Per Concrete type (TPC) – The last strategy is using one table per concrete type. So in our case this would be two tables for Agent and PotentialBuyer. Each table will also hold the columns of the base type person. Using the first strategy (TPT) all base type data gets into its own table.

Having explained the possibilities of mapping class hierarchies to a relational database, we will go with the second strategy “Table Per Hierarchy” which is the most intuitive one. So here is the code for the three entity classes:

public abstract class Person
{
   public int Id { get; set; }
   public string FullName { get; set; }
}

public class Agent : Person
{
   public ICollection Properties { get; set; }
}

public class PotentialBuyer : Person
{
   public double MaxPrice { get; set; }
}

As shown in the above code Agents can have multiple objects (properties) for selling, while PotentialBuyers usually have some MaxPrice they are willing to pay. This is the simple Domain Model we will be using to create, save and load some data utilizing the EF 4.

4. DbContext and DbSet<TEntity>

When working with the standard EntityFramework there are two classes that are really important and often used: ObjectContext and ObjectSet. The new Feature CTP introduces two new simplified abstractions of these classes: DbContext and DbSet<TEntity>. There are several reasons why the new classes were introduced, one of them being full backward compatibility. So it is up to you wether you use the classic versions (Entity Designer Support e.g.) or the new ones which are essentially made for the Code-First flavor.

I created a class RealEstatePropertyCatalog which inherits from DbContext and called it (RealEstateProperty)Catalog, because it does not only allow to load or save entities, but it also gives access to DbSets of all entity types like DbSet<Agent> for example:

public class RealEstatePropertyCatalog : DbContext
{
    public RealEstatePropertyCatalog(DbModel model)
        : base(model)
    { /* nothing here */}

    public DbSet Properties { get; set; }
    public DbSet
 People { get; set; }
    public DbSet Agents { get; set; }
    public DbSet
 Buyers { get; set; }
    public DbSet
<address> Adresses { get; set; }

    ///
    /// Here you can customize Schema related things.
    ///
    ///
<span> </span>The model builder.
    protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity
()
            .MapHierarchy()
            .Case
(person => new { person.Id, person.FullName, Discriminator = 0 })
            .Case(agent => new { agent.Properties, Discriminator = 1 })
            .Case
(potentialBuyer => new { potentialBuyer.MaxPrice, Discriminator = 2 })
            .ToTable("dbo.Contacts");
    }
}

Besides the DbSet Properties the override of the OnModelCreating method is important. Here you can customize different aspects of the model creation. The above code is mainly using this feature for mapping class hierarchies to a single table using a descriminator. You can see the the call to MapHierarchy() for the Person entity and then following a Case construct to define the mappings for each type of the hierarchy. Note the Discriminator information to differentiate between them. Also the ToTable() Method defines the name of the table within SqlServer. Inside OnModelCreating you can fully customize the way the model is being built, but we’re not going to dig here much deeper for now.

5. Mapping (Configuration)

The next class we are looking at is RealEstatePropertyConfiguration. This is a mapping class and contains all information about what properties of an entity should be written into which column of the table. In the first release of the Entity Framework this sort of “external” mapping was not available so many people denied using it. NHibernate for example is offering this feature for years. Using the standard EF 4.0 you would have to define the Ids (Primary Keys) of all your entities here and everything else like relations. The Feature CTP and its Conventions takes care of all that for you. Actually you don’t need the class below, but I threw it in for reference purposes so that you can see how you’d normally map a class to the Database. Pretty nifty timesafer!  :)

public class RealEstatePropertyConfiguration : EntityConfiguration
{
    public RealEstatePropertyConfiguration()
    {
        HasRequired(property => property.ContractedBy).WithMany(a => a.Properties);
    }
}

6. EF Configuration

Now we will take a look at configuring our Code-First solution. The configuration code can be found inside the Bootstrapper class. This code could also be inside the main method but I just decided to move it into a new class to separate the configuration code a little from the rest. The whole configuration code is placed inside the Run Method:

internal class Bootstrapper
{
    public DbModel Run()
    {
        // Takes the connection string from the app.config
        Database.DefaultConnectionFactory =
                      new SqlConnectionFactory("RealEstatePropertyCatalogConnectionString");

        #region Database Initialization

        // Changes in the DomainModel cannot be applied (yet) without
        // dropping the old database. Therefore changes result in an
        // Exception unless you force a db drop and recreate it.

        // additional strategies: (names are self-explanatory)
        // Database.SetInitializer(
                // new AlwaysRecreateDatabase());
        // Database.SetInitializer(
                // new CreateDatabaseOnlyIfNotExists());
        // Database.SetInitializer(
                // new RecreateDatabaseIfModelChanges());

        // switch off Generation if you have an existing Database
        //Database.SetInitializer(null);
        Database.SetInitializer(new RealEstatePropertyInitializer());

        #endregion

        var builder = new ModelBuilder();
        builder.Configurations.Add(new RealEstatePropertyConfiguration());
        builder.Entity
();
        builder.Entity
<address>();
        builder.Entity();

        return builder.CreateModel();
    }
}

Line 6 sets the DefaultConnectionFactory. There are predefined Factories like the SqlConnectionFactory (Sql Server) which can take a ConnectionString name. The ConnectionString is defined inside the app.config so choosing different EF configurations depending on your enviroment (Production, Development, Testing) can be easily achieved. Lines 20 to 26 are showing the available strategies for seting up your database when running the Bootstrapper, which is usually when starting the solution. Line 26 even shows a custom implementation (RealEstatePropertyInitializer), but let’s look at the standard strategies first, although the names are pretty self-explanatory:

  • AlwaysRecreateDatabase - This strategy always drops the whole database and recreates it. This is helpfull for full integration testing when an untouched db is what you need before every test.
  • CreateDatabaseOnlyIfNotExists - If no database is found it will be created by the Entity Framework.
  • RecreateDatabaseIfModelChanges - This only recreates your database if the underlying model (also the mapped entities) were changed.
  • Custom - You can implement your own strategies which is what I did in the demo app.
  • null - If you don’t need any initialization (read only or pre-existent database f.e.) you can just turn it off.

Again a static method (SetInitializer) on the Database class can be used to set the initializer like we did before, when setting the DefaultConnectionFactory. It takes an instance of a recreation strategy. If you want to turn this feature off just put in null as parameter. I already said that you can implement your own custom strategy, but how does it work exactly?!

public class RealEstatePropertyInitializer : AlwaysRecreateDatabase
{
    protected override void Seed(RealEstatePropertyCatalog context)
    {
        var agent1 = new Agent {FullName = "Paula Waters"};

        var prop1 = new RealEstateProperty {ContractedBy = agent1};
        var prop2 = new RealEstateProperty {ContractedBy = agent1};
        var prop3 = new RealEstateProperty {ContractedBy = agent1};

        agent1.Properties = new List {prop1, prop2, prop3};

        context.Agents.Add(agent1);
    }
}

This is a simple custom Initializer which inherits from the AlwaysRecreateDatabase strategy and afterwards put some init data into the database using the context.Agents.Add call.

Back to the last lines of the Run Method: Here we are just adding our configuration to the ModelBuilder, then we add all types we need in our model and finally call CreateModel which is the last thing to do before starting to utilize the Entity Framework. Now everything following is how to write /read data from the database using EF.

7. Putting some data in and querying it

Inside the Program.cs file you can find the Main method which contains all the data access code within an using statement for the RealEstatePropertyCatalog. Using such a Context/Catalog object is easily underestimated. There is a brilliant blog entry by Ayende Rahien on this topic for NHibernate which can be translated to EF. Just replace the word ISession with DbContext/ObjectContext in your Head: http://msdn.microsoft.com/en-us/magazine/ee819139.aspx. Having said that let’s look at the last section. Inside the Main method we are creating an object graph, then add it to the context and call SaveChanges on it. Afterwards we can execute queries using LINQ against the DbSets within our Catalog.

8. Summing it up

That’s about it. I hope I managed to show you the ease of using the new EF, while still achieving persistance ignorance through using the Code-First model. I was pretty impressed when I first used the new Feature CTP and although it is not perfect yet, I believe it’s heading into the right direction. Let me know if this demo helped you and what you are thinking of the Feature CTP.

Best regards

Gope

SOURCE CODE: DOWNLOAD

Follow

Get every new post delivered to your Inbox.