I was excited to see StottGu’s blog regarding Code-First Development with Entity Framework 4.  Personally, I don’t learn best by going through a step by step tutorial, however.  It’s like learning a song in another language by rote memory.  It may sound the same when I parrot it back, but don’t ask me to improvise.  So I began to apply the principles in the article to the particular problem I was working on – and applying it in a TDD fashion, which is what this particular functionality was developed for.

The first thing I did was to create some classes that I would begin using – simple models.  If simple model classes violate TDD, then just sue me.  Hey, it was a code spike!


using System.Data.Entity;
using System.Collections.Generic;

namespace Microsoft.SnapId.DomainModel
{
    public class ManagementAgentModel
    {
        public int ManagementAgentModelID { get; set; }
        public string Name { get; set; }

        public virtual ServerConfigurationModel ServerConfigurationModel { get; set; }
    }
    public class ServerConfigurationModel
    {
        public int ServerConfigurationModelID { get; set; }
        public string Title { get; set; }

        public virtual ICollection<ManagementAgentModel> ManagementAgentModels { get; set; }
    }
    public class SnapIDs : DbContext
    {
        public DbSet<ServerConfigurationModel> ServerConfigurationModels { get; set; }
        public DbSet<ManagementAgentModel> ManagementAgentModels { get; set; }
    }
}

Then in a separate DAL layer I placed the only code that was even remotely identifiable as DB interfacing:


using System.Collections.Generic;
using System.Linq;
using Microsoft.SnapId.DomainModel;

namespace Microsoft.SnapId.DataAccessLayer
{
    public class ServerConfigurationModelRepository
    {
        public ICollection<ServerConfigurationModel> GetAll()
        {
            var snap = new SnapIDs();

            var serverConfigs = from s in snap.ServerConfigurationModels select s;

            return serverConfigs.ToList();
        }


        public void Add(ServerConfigurationModel serverConfig)
        {
            var snap = new SnapIDs();

            snap.ServerConfigurationModels.Add(serverConfig);
            snap.SaveChanges();

        }
    }
}

And finally, I created a simple spike to test out the functionality:


using System.Collections.Generic;
using Microsoft.SnapId.DataAccessLayer;
using Microsoft.SnapId.DomainModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.SnapId.Tests.IntegrationTests.DataAccessLayer
{
    [TestClass]
    public class ServerConfigurationModelRepositoryTests
    {
        [TestMethod]
        [TestCategory("IntegrationTests")]
        public void Does_this_even_work()
        {
            var target = new ServerConfigurationModelRepository();

            var serverConfig = new ServerConfigurationModel
                                   {
                                       Title = "Foo"
                                   };

            target.Add(serverConfig);

            ICollection<ServerConfigurationModel> result = target.GetAll();

            Assert.IsNotNull(result);
        }
    }
}

Notice anything missing?  There is no config file so far – no connection string.  So I ran the test, completely expecting a failure.  Lo and behold, however, the test passed.  “OK,” I thought.  “Maybe there’s some sort of internal model of the data that doesn’t complain even if there’s no database.  Weird, but what more can you expect from a CTP?”

So I ran the test again, setting a breakpoint at the “GetAll()” method.  I saw two results come back instead of one!  Wow!  Usually “surprise” is a bad thing in relation to technology (or so we’ve been taught), but this was definitely a good surprise.  So I dug into the data that came back and found what was going on.  Here’s an imaginary conversation that I was having with the Entity Framework 4:

Me:  Ok, go run this code.  I know it’s not going to work, but run it anyway.

EF4: Do you nave SqlExpress installed?

Me: Uh, yeah.  I have VS 2010 installed, so that’s pretty much a given.

EF4: OK then, let me go ahead and decipher your object model and create you a new DB in your SqlExpress instance.  Let’s see… I think I’ll call it the DB “Microsoft.SnapId.DomainModel.SnapIDs” after your object model.

Me: Whoa!  That’s incredible!  I’ll never have to deal directly with a database ever again!

EF4:  Now you’re just dreaming.

Me:  I can always dream.

 

Well, OK, it wasn’t quite that smooth.  I did have an issue where I named my ID fields like “ManagementAgentModelId” instead of “ManagementAgentModelID”  and EF4 wasn’t happy with that – said it couldn’t decipher a primary key for the object.  Apparently it wasn’t case insensitive, which is a bummer, because you don’t spell it “IDentifier” – that’s like an interface for your teeth or something.

In the end, I am quite pleased with the code-first capability of EF4.  I think I’ll call it “code-fist” from now on – sounds more dynamic.