Tuesday, June 24, 2008

A vote of confidence for the Entity Framework

I saw a post from the alt.net community here saying the EF was crap basically....http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/

The core complaints raise some important issues, but i really don't think we need to go ballistic, and in some cases the concerns are just plain wrong. Time would be better spent finishing the Linq for NHibernate provider don't you think??

I've been working solidly with EF since the SP1 beta came out and can honestly say it's holding up very well across a large, enterprise data model structure, and alongside usage of a repository pattern and dependency injection to factor out most of the direct dependencies on the EF ObjectContext, we have a system that can move towards POCO over time with relatively little refactoring.

Here's some of my responses:

The design of the framework entities is that they are data only, causing issues in maintainability and making it difficult or impossible to implement business objects or more “real-world” objects. 
Wrong, you use partial classes to extend the generated aspects of the entities. This is explicitly encouraged and we use it a lot for core business rules and validation. There is nothing to stop you adding new non persistent properties or methods, or indeed new classes that are used alongside the entities.

The design of the framework entities is that they cannot be persistence ignorant, so things like unit testing become next to impossible because you cannot test the model without the database (for instance).
There are (admittedly difficult) ways to get close to POCO. Rather than tear your hair out, we used the repository pattern around the EF and avoid using the object context directly. You are then only dependent on EntityObject, EntityReference and EntityCollection on your entities. If you are sensible about it and don't work on object context, your refactoring when vnext comes along will be significantly reduced. This is a happy compromise for us and works well.

Lazy loading is not supported at all and requires a lot of extra code to make work.  This confuses me.  I thought I saw "lazy-loading" demoed internally but I might be mistaken.
KP > 'By design';) but honestly pretty easy to wire it up, not really a "lot of extra code". I have worked for years with NH too, and the time saved using the designer with EF more than makes up for it:)

Shared, canonical models contradict software best practices.  This appears to be related to using a single shared model for multiple contexts in the EF, rather than multiple models, one for each individual context. 
KP > Well, it may be a criticism of the vision of EF (the more than just an ORM story), but not of its core ORM functionality. Our clients are interested in the reporting aspects on their entity models without writing excessive code. It remained to be seen how this will pan out, but surely this is not a reason to pledge a vote of no confidence in a piece of technology?

Excessive merge conflicts with source control.  Apparently, since the diagram contains the model and the visualization, it causes tons of merge conflicts when a team is using it.
A somewhat moot point for most teams. We've settled on having a 'domain master', not a biggy for most teams? shared design on the database, entities and relationships would get messy in the best of worlds, i don't think this is a biggy.

Tuesday, June 24, 2008 5:22:28 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [6]  |  Trackback
 Thursday, May 29, 2008

Polymorphic Repository for ADO.Net Entity Framework

Wow, what a sexy title!

This post shows how you can have a repository pattern with the entity framework .

So, here we have a generic repository interface through which you can do all the nice things. You would normally use Castle Windsor (or similar Dependency Injection tool) to configure the Repository implementation (such as EFRepository) so you then just have a dependency on the interface, which is nice. Here's a snippet of how to configure the EFRepository to be used for all requests for IRepository from Castle Windsor. Note the ability to change object contexts and even the repository implementation, as long as IRepository is supported, the application won't care.

<castle>
    <components>

         <component id="objectContext" type="YourObjectContext"  ></component>
      <component id="iEFRepository" service="YourIRepository" type="YourEFRepository"
        <parameters>
          <objectContext>${objectContext}</objectContext>
        </parameters>
      </component>
    </components>
  </castle>

Note the reflection in the EFRepository implementation which allows you to query and work with all types in a hierarchy. By default you can't work directly with sub types in EF, you have to do extra work to get to them. The reflection gets the base type before communication with the ObjectContext to ensure minimal fussing about for the developer. Note i don't understand why this isn't built in to be honest, perhaps they ran out of time!

The whole point of this is that you avoid using your application's ObjectContext explicitly and only work with the core business entities that are then managed by the Entity Framework. This allows us to have a good separation of concerns between the various layers (although our entities are not pure POCO sadly). Note that i have only exposed the most widely used features of ObjectContext, you can extend your Repository interface and implementation to expose more advanced parts of the ObjectContext implementation if needs be.

In the future, EF may move towards greater persistence ignorance, but in the mean time structuring your application working off a Repository interface will mean minimal changes as EF changes moving forwards.

IRepository interface

public interface IRepository
  {

      /// <summary>
      /// Return reference to an underlying repository context
      /// </summary>
      /// <returns>the repository context</returns>
      object GetRepositoryContext();

      /// <summary>
      /// Return strongly typed IQueryable
      /// </summary>
      IQueryable<T> GetQuery<T>();

      /// <summary>
      /// Load entity from the repository or store if necessary
      /// </summary>
      /// <typeparam name="T">the entity type to load</typeparam>
      /// <param name="where">where condition</param>
      /// <returns>the loaded entity</returns>
      T Load<T>(Expression<Func<T, bool>> whereCondition);

      /// <summary>
      /// Mark entity to be deleted within the repository
      /// </summary>
      /// <param name="entity">The entity to delete</param>
      void Delete<T>(T entity);

      /// <summary>
      /// Add entity to the repository
      /// </summary>
      /// <param name="entity">the entity to add</param>
      /// <returns>The added entity</returns>
      void Add<T>(T entity);

      /// <summary>
      /// Updates entity within the the repository
      /// </summary>
      /// <param name="entity">the entity to update</param>
      /// <returns>The updates entity</returns>
      void Update<T>(T entity);

      /// <summary>
      /// Save all changes from repository to store
      /// </summary>
      /// <returns>Total number of objects affected</returns>
      int SaveChanges();

  }

Now we have our proper EFRepository.......

EFRepository implementation

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public class EFRepository : IRepository, IDisposable
  {
      private ObjectContext _objectContext;

      private Type GetBaseType(Type type)
      {
          Type baseType = type.BaseType;
          if (baseType != null && baseType != typeof(EntityObject))
          {
              return GetBaseType(type.BaseType);
          }
          return type;
      }

      private bool HasBaseType(Type type, out Type baseType)
      {
          Type originalType = type.GetType();
          baseType = GetBaseType(type);
          return baseType != originalType;
      }

      public EFRepository(ObjectContext objectContext)
      {
          _objectContext = objectContext;
      }

      public ObjectContext ObjectContext
      {
          get
          {
              return _objectContext;
          }
      }

      public object GetRepositoryContext()
      {
          return this.ObjectContext;
      }

      public IQueryable<T> GetQuery<T>()
      {
          Type baseType;
          if (HasBaseType(typeof(T), out baseType))
          {
              return this.ObjectContext.CreateQuery<T>("[" + baseType.Name.ToString() + "]").OfType<T>();
          }
          else
          {
              return this.ObjectContext.CreateQuery<T>("[" + typeof(T).Name.ToString() + "]");
          }
      }

      public T Load<T>(Expression<Func<T, bool>> whereCondition)
      {
          return this.GetQuery<T>().Where(whereCondition).First();
      }

      public void Add<T>(T entity)
      {
          this.ObjectContext.AddObject(GetBaseType(typeof(T)).Name.ToString(), entity);      
      }

      public void Update<T>(T entity)
      {
          EntityObject entityObject = entity as EntityObject;
          ObjectContext objectContext = this.ObjectContext;
          objectContext.ApplyPropertyChanges(
              GetBaseType(typeof(T)).Name.ToString(),
              objectContext.GetObjectByKey(entityObject.EntityKey)
          );
      }

      public void Delete<T>(T entity)
      {
          this.ObjectContext.DeleteObject(entity);
      }

      public int SaveChanges()
      {
          return this.ObjectContext.SaveChanges();
      }

      public void Dispose()
      {
          if (_objectContext != null)
          {
              _objectContext.Dispose();
          }
      }

  }

Thursday, May 29, 2008 4:13:14 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 20, 2008

FriendFeed is cool

http://friendfeed.com/kpatton contains a list of all my online activity, essentially blog posts, youtube, flickr and twitter stuff. Nice idea, although there seems to be a new social networking site every 5 minutes and i'm struggling to keep up!

Tuesday, May 20, 2008 7:07:04 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, May 07, 2008

Four Generations of Pattons

Here's Annable, wee Tommy, me and my grandfather (Thomas Patton, wee Tommy's great grandfather, just turned 89) with my grandmother Dorothy. Also picture is my dad, my Auntie Ruth and Uncle Tom.

Tommy was named after my grandfather, whose father was also called (guess what?) Thomas.

In other photos you can see the famous Patton's Place, Ballyhalbert!

04052008425

04052008428

04052008431

Wednesday, May 07, 2008 8:18:17 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Tommy Chasing Bubbles during Sunset

Wednesday, May 07, 2008 8:06:06 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Videos from Donegal Trip

Wednesday, May 07, 2008 8:04:29 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Tommy on the Lawnmower

no fear as tommy mows the lawn

Wednesday, May 07, 2008 7:46:43 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, May 04, 2008

The search for a bowl of stew and a decent coffee

donegal pics
Sunday, May 04, 2008 10:03:09 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, April 28, 2008

Tommy Birthday Pics

Here's some selected pics from the day, all the pics from our uk tour at http://blog.keithpatton.com/2008/04/23/UK+Tour+Pics.aspx

270420083042704200830127042008295270420082942704200829327042008292TommyHaroldBaloon27042008321

Monday, April 28, 2008 8:00:33 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Tommy's Unofficial 2nd Birthday Party

Some videos from tommy's birthday party at my dad's.

All pics added to the main uk tour pics slideshow at:

http://blog.keithpatton.com/2008/04/23/UK+Tour+Pics.aspx

Monday, April 28, 2008 7:45:46 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, April 25, 2008

Tommy the Flower Child

Sitting on a log at the end of my dad's garden.

 

24042008280

Friday, April 25, 2008 8:30:25 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Everyone needs a cuddle

Hey, who's this? It's Billy, and he's been out in the cold all night long.

24042008281

Aww.. in the interests of peace and reconciliation, he gets a bit of love from tommy.

24042008284

Friday, April 25, 2008 8:28:38 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, April 23, 2008

UK Tour Videos

Worked out how to embed the flickr videos! here's the first batch..

Wednesday, April 23, 2008 10:05:05 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [1]  |  Trackback

UK Tour Pics

Back in the land of fudge bars, chomps, world snooker, football on  at the right time, jade goody and dusty chaotic airports! All the pics will be updated in the slideshow below. Am also uploading videos now via flickr instead of youtube because it's easier to do it all to the one place. but i haven't worked out how to display the videos yet!

Wednesday, April 23, 2008 9:53:58 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback