This blog as moved to: http://nerditorium.danielauger.com/

Persistence Ignorant Lazy Loading For Your Hand-Rolled DAL In .NET 4.0 Using Lazy<T>


This post is a brief update to the .NET 3.5 article I posted about P.I. lazy loading. The only major change I have made to the code is to use the new Lazy<T> class that was introduced in .NET 4.0. This considerably cleans up the LazyLoadingList<T> class from the previous post.

Here is the new LazyLoadingList<T>:
public class LazyLoadingList<T> : IList<T>
{
private Lazy<IList<T>> _lazyList;

public LazyLoadingList(Lazy<IList<T>> lazyList)
{
_lazyList = lazyList;
}

#region Implementation of IEnumerable

public IEnumerator<T> GetEnumerator()
{
return _lazyList.Value.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return _lazyList.Value.GetEnumerator();
}

#endregion

#region Implementation of ICollection<T>

public void Add(T item)
{
_lazyList.Value.Add(item);
}

public void Clear()
{
_lazyList.Value.Clear();
}

public bool Contains(T item)
{
return _lazyList.Value.Contains(item);
}

public void CopyTo(T[] array, int arrayIndex)
{
_lazyList.Value.CopyTo(array, arrayIndex);
}

public bool Remove(T item)
{
return _lazyList.Value.Remove(item);
}

public int Count
{
get
{
return _lazyList.Value.Count;
}
}

public bool IsReadOnly
{
get
{
return ((ICollection<T>)_lazyList.Value).IsReadOnly;
}
}

#endregion

#region Implementation of IList<T>

public int IndexOf(T item)
{
return _lazyList.Value.IndexOf(item);
}

public void Insert(int index, T item)
{
_lazyList.Value.Insert(index, item);
}

public void RemoveAt(int index)
{
_lazyList.Value.RemoveAt(index);
}

public T this[int index]
{
get
{
return _lazyList.Value[index];
}
set
{
_lazyList.Value[index] = value;
}
}

#endregion
}


Here are the changes to the invoking code:
public class CompanyDAO : ICompanyDAO
{
List<Company> _companiesInDatabase = new List<Company>
{
new Company(){Name = "ACME"},
new Company(){Name = "Hardees"}
};

#region Implementation of ICompanyDAO

public Company GetByName(string name)
{
// Write to console to demonstrate when loading is happening
Console.WriteLine("---Loading Company---");

// Pretend we are calling / mapping from a store procedure
var company = _companiesInDatabase.Where(x => x.Name == name).First();


// Create / add the lazily loaded collection
if (company != null)
{
var lazyLoader = new Lazy<IList<Employee>>(
() =>
{
var employeeDAO = new EmployeeDAO();
return employeeDAO.GetByCompanyName(name).ToList();
}
);

company.Employees = new LazyLoadingList<Employee>(lazyLoader);
}

return company;
}

#endregion
}


The full source can be found here: http://github.com/dauger/BlogSamples

How to fail at ORM

NoORM


Let's face it: if trends continue, some form of ORM will be a fact of life at most .net organizations that develop business / enterprise software. Microsoft isn't playing games this time with Entity Framework. They mean for it to succeed. Additionally, at the time of writing this, NHibernate has been downloaded 391,024 times from sourceforge alone (there is more than one place to download it from). This being the case, I’m going to give everyone a few pointers to ensure that their first attempt at ORM fails.

Here are my tips to insure ORM adoption failure (in no particular order):

Consider the ORM’s SQL engine as a replacement for SQL knowledge. The whole point behind ORMs is so that I don’t have to write or understand SQL right? WRONG!

Consider the ORM’s SQL engine to be a black box. I got back the correct dataset, so this must be the best SQL the ORM can produce right? WRONG! Most ORMs will create drastically different SQL depending on how the object query is structured.

Don’t get more than a skin deep understanding of the ORM. If you run into a brick wall with a bit of behavior from the ORM, you can follow two paths. You can A) learn about the finer points of the ORM to resolve the issue, or B) rip the ORM out of your application. The latter is the outcome I’ve seen more often than not. A classic example of this is the N+1 select issue where the app calls the database in a loop. ORMs have things such as eager loading, multi-queries, and future queries to avoid extra trips to the database. However, it’s best to ignore the existence of those features if you want to fail at ORM.

Use ORM generated schema without manually tweaking it. Many ORMs will happily create a schema for the developer just how they specified it, and index free. Ideally you shouldn’t use generated schema at all once you are up and running. A DBA should be creating a schema using relational theory. However, if you want to fail, it’s best to just used that generated schema.

Use the ORM for 100% of your data access.
Most ORMs allow for dropping into prepared SQL, stored procedures, and even db function calls. However, it’s best to ignore this functionality if you want to fail.

Maintain OO purity at all costs.
Does fetching your aggregate root cause an 11 table join? So be it.

Cut the DBA out of the development process.
The whole point of ORM is to cut out the DBA right? WRONG! The DBA should be just as active with helping to craft the data access strategy as they would with a hand rolled data access layer. Cutting the DBA of the picture is a recipe for failure.

Don’t profile your application.
If you want to fail, it’s best to find out if you have have created a SQL nightmare once you hit production. NHProf, EFProf, L2SProf, and SQL Profiler are your friends. Ignore them to fail.

I hope you find these tips helpful. I’d like to hear about any other tips for ORM failure you might have.