Friday, August 15, 2008

Tommy has a new bed

Friday, August 15, 2008 12:47:57 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [1]  |  Trackback

Tommy Goes on Holiday

Friday, August 15, 2008 12:37:04 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, August 09, 2008

Tamaki Drive Sunset

All i can say is roll on spring....Probably my favouritest part of auckland is the tamaki drive stretch out east. And sometimes you get blindingly beautiful sunsets back across the city view.

08042008231

Saturday, August 09, 2008 10:16:26 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, August 05, 2008

Tommy gets a new bed

Tommy is officially a big boy now he has his own bed. He even wants to go to bed early at the moment, not sure how long that will last though!

 

02082008524

Tuesday, August 05, 2008 1:34:13 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, July 20, 2008

Christchurch Weekend

Sorry lucy, no pictures of tommy as yet, here's some snaps of our weekend down at christchurch/hamner springs. Will some trees do instead??

DSC03537DSC03538DSC03539DSC03541DSC03542DSC03544DSC03546DSC03550DSC03557

Sunday, July 20, 2008 4:24:11 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, July 13, 2008

Sorry Lucy, more pics coming soon

Lucy just reminded me that i must post mroe family pics soon. She however requesed pics of tommy explicitly even though i'm undoubtedly more handsome, strange...

Here's one of us in London to keep you going lucy.

DSC03511

Sunday, July 13, 2008 8:44:48 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, July 04, 2008

Entity Framework Lazy Loading - A quick alternative with extension methods

I saw the following code on a customer object which made me think about affording a better way to query domain relationships without the extra methods, extension methods come to the rescue!

I realise transparent lazy loading a la Nhibernate is another option, but i think that this way keeps the spirit of explicitly loading from the database, but reduces the amount of code clutter on the client side so you are not forever checking whether a relationship is loaded or not, you simply request an IQueryable from the EntityCollection<T>.

        /// <summary>
        /// Finds a customer account with the specified ID
        /// </summary>
        /// <param name="customerAccountID">ID of the customer account to find</param>
        /// <returns>Customer account with the specified ID</returns>
        public CustomerAccount FindAccount(int customerAccountID)
        {
            if(!this.CustomerAccounts.IsLoaded)
            {
                this.CustomerAccounts.Load();
            }

            var query =
                from ca in this.CustomerAccounts
                where ca.CustomerAccountID == customerAccountID
                select ca;

            return query.FirstOrDefault();
        }

I added a static class with the extension methods for the EntityCollection type as follows:

public static class EntityCollectionExtensions
    {
        public static EntityCollection<T> EnsureLoaded<T>(this EntityCollection<T> entityCollection) where T : class, IEntityWithRelationships
        {
            if (!entityCollection.IsLoaded)
                entityCollection.Load();
            return entityCollection;
        }

        public static IQueryable<T> AsQueryable<T>(this EntityCollection<T> entityCollection, bool ensureLoaded) where T : class, IEntityWithRelationships
        {
            if (ensureLoaded)
                entityCollection = EnsureLoaded<T>(entityCollection);
            return entityCollection.AsQueryable();        }
    }

This allows you to do the following, which will only go to the database if the relationship is not loaded.

            var query =
                from ca in this.CustomerAccounts.AsQueryable(true) // ensure the relationship is loaded and return a queryable on it
                where ca.CustomerAccountID == customerAccountID
                select ca;
    return query.FirstOrDefault();

Friday, July 04, 2008 8:44:57 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 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