BusinessRx Community

Dedicated to the advancement of software, technology and the people who devote their lives to it.

Welcome to BusinessRx Community Sign in | Join | Help
in Search

BusinessRx Reading List

These blog entries are written by industry experts and leaders. We consider this content to be a good read for any software developer or web technologist.

Trying Out Persistence Ignorance with LINQ (Part II)

In Part I, we defined an IUnitOfWork interface to avoid coding directly to the System.Data.Linq.DataContext class. IUnitOfWork gives us the opportunity to manipulate IDataSource<T> objects.

IDataSource<T> is another abstraction. When the software is running in earnest, we need to back an IDataSource<T> with a table in a SQL Server database. However, during unit testing we might prefer to have an IDataSource<T> backed by an in-memory data structure. Essentially, we want the ability to switch between a System.Data.Linq.Table<T> implementation (SQL Server) and a System.Collections.Generic.List<T> implementation (in-memory) - without changing the code and LINQ expressions in the upper layers of software.

Fortunately, a handful of interfaces define every Table<T> object. If we implement the same interfaces, we can walk and talk just like a real Table<T>.

public interface IDataSource<T> : IQueryable<T>, IEnumerable<T>,
                                 
ITable, IQueryProvider
{

}

Implementing a persistent data source, one that talks to SQL Server, is as simple as forwarding the calls to an underlying Table<T> implementation.

class PersistentDataSource<T> : IDataSource<T> where T: class
{
    
Table<T> _table = null;
    
DataContext _context = null;
  
    
public PersistentDataSource(DataContext context)
    {
        
Check.ArgIsNotNull(context, "context");

        _context = context;
        _table = context.GetTable<T>();

        
Check.IsNotNull(_table, "Could not retrieve table for "
                                +
typeof(T).ToString());
    }

    
void ITable.Add(object o)
    {
        ((
ITable)_table).Add(o);
    }

    
public IQueryable CreateQuery(Expression expression)
    {
        
return ((IQueryProvider)_table).CreateQuery(expression);
    }
    

    
// ...

Implementing an in-memory data source is a little bit trickier, but appears possible thanks to extension methods like AsQueryable on the System.Linq.Queryable class.

class InMemoryDataStore<T> : IDataSource<T>
{
    
List<T> _list = new List<T>();

    
public void Add(object entity)
    {
        _list.Add((T)entity);
    }

    
public IQueryable CreateQuery(Expression expression)
    {
        
IQueryable queryable = _list.AsQueryable();
        
return queryable.Provider.CreateQuery(expression);
    }
    
    
// ...

Of course, this naïve implementation could never support the full application, but should be suitable for the majority of isolated unit tests.

In the next post, we'll tie everything together to see how all these abstractions work together.

In the meantime, read Rick Strahl's "Dynamic Expression in LINQ to SQL". It is scenarios like the ones that Rick is presenting that make me worry that this approach will fall apart when it hits real requirements.

Published Tuesday, August 28, 2007 10:32 PM by OdeToCode Blogs

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server, by Telligent Systems
'