Using Entity Framework 4.0 CTP

In this post I will take a look at the new features in the next release of entity framework.

Primary feature set is centered around what is commonly referred to as “Code First” approach to Entity Framework.  With code first approach you write the code first, then entity framework runtime dynamically figures out how to persist your classes to database.

So, you start with plain ol’ LCR classes (POCO classes).  For my small example I will have list of companies with their contacts.  Here is what my classes look like:

        public Company()
        {
            Contacts = new ObservableCollection<CompanyContact>();
            Contacts.CollectionChanged += (o, e) =>
                {
                    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                    {
                        foreach (var item in e.NewItems)
                        {
                            (item as CompanyContact).ParentCompany = this;
                        }
                    }
                };
        }
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
        public DateTime DateAdded { get; set; }
        public virtual ObservableCollection<CompanyContact> Contacts { get; private set; }
    }
 
    public class CompanyContact
    {
        public int CompanyContactId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Company ParentCompany { get; set; }
    }

 

Now we need to take a look at key classes that enable POCO persistence in Entity Framework CTP : DbSet and DbContext.

DbSet is a set of POCO classes that is pretty much a simplified version of ObjectSet.  It gives developers ability to add and remove items to.  DbContext is really at heart of CTP version, and it is a simplified version of ObjectContext.  It may contain any number of properties that are of type DbSet<T> where T is any POCO class.

Here is what this class looks like for my Rolodex mini-application:

    public class CompanyContext : DbContext
    {
        public CompanyContext()
            : base()
        {
        }
        public DbSet<Company> Companies { get; set; }
 
        public DbSet<CompanyContact> Contacts { get; set; }

 

That is all we need to do at a high level, dealing with out POCO classes.  Now, the key part – let’s define our rules and persistence details.  There is a number of ways this can be done, I am picking virtual method OnModelCreating on DbContext that allows me to configure rules and persistence details.  Here is what I am doing for my couple of classes:

        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
 
            // configure primary key
            modelBuilder.Entity<Company>()
                .HasKey(c => c.CompanyId);
 
            // company id is identity
            modelBuilder.Entity<Company>().Property(c => c.CompanyId)
                .StoreGeneratedPattern = System.Data.Metadata.Edm.StoreGeneratedPattern.Identity;
 
            //maximum length for company name
            modelBuilder.Entity<Company>()
               .Property(c => c.CompanyName).MaxLength = 40;
 
            //name required
            modelBuilder.Entity<Company>()
                .Property(c => c.CompanyName).Optional = false;
 
            // One to many relationship
            modelBuilder.Entity<Company>()
                .HasMany(c => c.Contacts);
 
            //contact id is identity
            modelBuilder.Entity<CompanyContact>().Property(c => c.CompanyContactId)
                .StoreGeneratedPattern = System.Data.Metadata.Edm.StoreGeneratedPattern.Identity;
 
            // primary key for contacts
            // company cannot be null
            modelBuilder.Entity<CompanyContact>()
                .HasKey(c => c.CompanyContactId)
                .HasRequired(c => c.ParentCompany);
 
            //last name required
            modelBuilder.Entity<CompanyContact>()
                .Property(c => c.LastName).Optional = false;
 
            //maximum length for last name
            modelBuilder.Entity<CompanyContact>()
                .Property(c => c.LastName).MaxLength = 50;
 
            //first name required
            modelBuilder.Entity<CompanyContact>()
               .Property(c => c.FirstName).Optional = false;
 
            //maximum length for first name
            modelBuilder.Entity<CompanyContact>()
              .Property(c => c.FirstName).MaxLength = 30;
 
 
        }

 

As you can see from my comments I am configuring nullable / non nullable properties via Optional properties off Property method.  I am also configuring Identity properties via StoreGeneratedPattern.  I am also configuring maximum length for my fields at the same time.

The next step is to create a database and add data.  Creating database is super easy with DbContext:

            using (var context = new CompanyContext())
            {
                context.Database.Connection.ConnectionString = @"Server=(local);Database=RolodexEFCtp;Trusted_Connection=True;";
                context.Database.CreateIfNotExists();

 

That is all that takes.  At the time my context is created, OnModelCreating will fire, thus configuring all my persistence options.  Now, let’s populate DB with data:

                var company = new Company()
                    {
                        CompanyName = "Mine",
                        DateAdded = DateTime.Now
                    };
                context.Companies.Add(company);
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "Sergey",
                    LastName = "Basrskiy"
                });
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "John",
                    LastName = "Doe"
                });
 
                company = new Company()
                {
                    CompanyName = "Yours",
                    DateAdded = DateTime.Now
                };
                context.Companies.Add(company);
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "Jane",
                    LastName = "Doe"
                });
 
                company.Contacts.Add(new CompanyContact()
                {
                    FirstName = "John",
                    LastName = "James"
                });
                context.SaveChanges();

 

As before, the last line of dealing with saving is calling SaveChanges() method. 

Now, let’s take a look at how to get the data back from database:

            using (var context = new CompanyContext())
            {
                context.Database.Connection.ConnectionString = @"Server=(local);Database=RolodexEFCtp;Trusted_Connection=True;";
                var companies = context.Set<Company>().Include("Contacts").OrderBy(c => c.CompanyName).ToList();
            }

 

The last line will get me the list of companies, each populated with the list of corresponding contacts.  At this point I am doing everything that Entity Framework is designed for – get me the data from database and save data to database, except now I am configuring everything in code and creating storage on the fly.  Most importantly, I use POCO classes instead of Entity classes.

Now we just have to wait and see when new version of Entity Framework is released.

You can download CTP here: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=4e094902-aeff-4ee2-a12d-5881d4b0dd3e&displaylang=en

You can find more details on CTP on entity framework team blog: http://blogs.msdn.com/b/adonet/archive/2010/07/14/ctp4codefirstwalkthrough.aspx

Thanks

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *