What I’m loving about the newest iteration of EF Code First in CTP4

There have been a lot of improvements to code first since CTP3 and in fact, the team has been experimenting with changes to the core Entity Framework APIs that not only support even simpler programming with code first but that we’ll benefit from in an upcoming release of .NET. (No, I don’t know if there will be a service pack and when…)

I have a code first sample in my book, Programming Entity Framework 2nd Edition, that is coming out in August and was lucky with the timing of the CTP4 release because I was able to sneak in an overhaul of that section before the book heads to the printer.

In revising my code sample for that section I was very happy with so many of the API & Code First improvements.

**But first a clarification is important. The version of Entity Framework that is in .NET 4/VS2010 is the current shipping, supported version that you can use in production. What’s in the CTP is simply an early look at what’s coming as it evolves giving us a chance to play with it. This is not something you can deploy and it is also going to evolve with future CTP versions.**

So with that in mind, I went to town on the CTP3 sample.

The first thing that I benefited from was the new stripped down easy access versions of the ObjectContext and ObjectSet.

The new classes, DbContext and DbSet have the same essential functions but don’t expose you to the entire feature set of their big brother & sister. Not everyone needs all of those features. The are not derived from ObjectContext and ObjectSet however, but provide easy access to the full featured versions through a property e.g., DbContext.ObjectContext and DbSet.ObjectSet.

Along with this simplification are simplified terms.

Where ObjectSet has AddObject

context.Customers.AddObject(myCust) – note that Customers in this case is the ObjectSet)

DbSet simply uses Add

context.Customers.Add(MyCust) –>now I’m using Customers as a DbSet).

Another nice trick is how DbSets are created.

ObjectSet has an internal constructor and does not have a parameterless constructor,so you need a backing variable

ObjectSet<Customer> Customers;

and then you need to execute the CreateObjectSet method to create the ObjectSet:

context.CreateObjectSet<Customer>(“Customers”)

DbSet has a constructor so you can use an auto-implemented property

public DbSet<Customer> Customers { get; set; }

Code First gets way easier

It’s true. I cut out gobs of code and moved code to where it belongs.

Code first uses convention over configuration. It looks at your classes and does its best job of inferring a model and a database schema from it (if you are starting from scratch). Your classes don’t always provide enough metadata so you can provide more info to code first through additional configurations. Initially those configurations were programmatic only but now you can also use attributes in your classes (“data annotations”).

Here are two examples.

In my model I have a class called ConferenceTrack. It has an identity property called TrackId. Code first convention looks for “Id” or class name + “Id” as an identity but TrackId doesn’t fit this pattern so I have to tell EF that this is my identity key.

I can do that using code first’s ModelBuilder (formerly called ContextBuilder):

modelBuilder.Entity<ConferenceTrack>().HasKey(ct => ct.TrackId);

In CTP3, I had to execute from the same code that instantiates the context. Bad bad. Now there is an OnModelCreating method that I can use and put that configuration inside that method. The method lives in the context class. I don’t have to call it. The context is smart enough to run it for me.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<ConferenceTrack>().HasKey(ct => ct.TrackId);
}

Alternatively, I can configure this key right in my class as an attribute of the TrackId property.

    [Key]
    public int TrackId { get; set; }

Definitely simpler. I prefer to keep all of that EF related stuff in the context class so will most likely continue to use the fluent configuration rather than the data annotations.

Boy oh Boy did Relationships Get Easier

In my domain classes, I have a bunch of relationships defined through properties.

E.g.

ConferenceTrack has

public ICollection<Session> Sessions  { get; set; }   (a one-to-many relationship)

Session has

  public ConferenceTrack ConferenceTrack { get; set; }  (a many to one relationship)
  public ICollection<Speaker> Speakers { get; set; } (a many to many relationship)

In CTP3 I had a whole bunch of configurations defined (that were hard to construct and hard to read) so that the model would understand my intent with these relationships. CTP4 is now smart enough to grok my intent based on the domain class properties. And if there’s something that I want that doesn’t follow the convention, then I can add a configuration.

So I removed *all* of the configuration code that described the relationships.

That made me happy.

And EF/Code First figured it all out.

Based on my classes and the single configuration to define the TrackId as the key for conferences, it created this database to persist my data into

ctp4

It worked out all of the relationships. Notice the Sessions_Speakers that it created for the many to many relationship.

Also, I have a class in my domain that is called Workshop and inherits from Session. By default Code First assumes Table Per Hierarchy. It created a discriminator column in the Sessions table which I need to use another configuration for to change its name to IsWorkshop.

There’s more to love about this CTP. You can get coding details from theEntity Framework Design and EF team blog’s newest posts and download the CTP here.

 As I’m learning more about domain driven development and as code first evolves, I’m getting more excited about this upcoming feature of Entity Framework

  Sign up for my newsletter so you don't miss my conference & Pluralsight course announcements!  

8 thoughts on “What I’m loving about the newest iteration of EF Code First in CTP4

  1. no. I did that video last week. CTP4 just came out 2 days ago 🙂 But am thinking about it. Not sure if P/S does future tech vids tho.

  2. What is the difference in ConfTrack relationship and many-many relationship. They look defined similarly – how does it work? I tried, it didn’t create the table for me!

    I wonder, what did I miss!

    Thanks in advance.

  3. @Sharad

    Session class has a property for conference track that is a single item.

    ConfTrack has a property that is a collection of sessions. So the classes tehmselves define a one to many rel between conftrack and session.

    Now to the *:*.

    Session has a property that is a collection of speakers.

    Speaker has a proeryt that is a collection of sessions

    That defines a many to many and EF created a join table to represent that in the db.

    hth

    julie

  4. Hey Julie,

    Will it do many-to-many with payload?

    Here’s what I need to do…

    Imagine a table of Projects, a table of Sites, and a table of Widgets.

    A Project has many Sites.

    A Site has many Widgets.

    However, since there are a huge number of widgets, when the user sets up a new Project, they pick a small subset of Widgets for use in each of the Sites in the Project.

    Seems to me that one would need a join table(Projects_Widgets) that joins to yet another join table (Sites_Projects_Widgets).

    I can figure out how to model this in Code-First so that I get the results I’m looking for. any ideas?

  5. Hi Julie,

    Thanks for the blog post! I’m doing something similar with a many-to-many relationship in my model, and I wanted to do something like:

    "Select all sessions that belong to Speaker A". The underlying SQL is obvious, but I had a little trouble writing the Linq query, since the Sessions_Speakers table isn’t exposed through the DataContext.

    I ended up doing this:

    var speakerId = 5; // assuming this value came from some selection criterion

    var sessions = Sessions.Where(s => s.Speakers.Select(y => y.SpeakerId).Contains(speakerId));

    Does this seem okay to you? It feels a little indirect this way, and I’m not sure if the underlying SQL statement is optimal.

    Thanks for your thoughts on this.

  6. @Thom

    You might want to look at using Any.

    WIthout intellisense to aid me, it could look something like

    sessions.Where(s=>s.Speakers.Where(sp=>sp.SpeakerId==speakerId))

    not guaranteed, but something I wolde certainly try

    Also take a look at the genrated tsql for both variations. If the end results (sql) are the same, then for writing the linq query, it then becomes a matter of personal style.

  7. Hi Julie,

    Good point, thanks for that. So, for anyone reading this later, I ended up using the equivalent of:

    var sessions = dc.Sessions.Where(s => s.Speakers.Any(sp => sp.SpeakerId == speakerId));

    where dc is my DataContext.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.