Testing Domain-Driven Design with Sterling for Windows Phone 7

November 10, 2010 | Unit Testing

When building applications targeting the Windows Phone 7 (WP7) you often need to create and maintain any kind of data. And while (for security reasons we all understand) you can't access the local file system, you can benefit from the Isolated Storage. It's API is similar with the one exposed in the Silverlight namespace. 

A good design of a Domain model knows nothing about persistence. You can use an in-memory database, a relational database, or ..an Object-Oriented Database for WP7 that works with Isolated Storage classes and supports full LINQ to Object queries over keys and indexes for fast retrieval of information from large data sets!” Enter Sterling.

Here is a sample repository implementation using Sterling to store and retrieve data:

internal class SterlingRepository<T> where T: class, new()
{
    public void Save(T instance)
    {
        App.Database.Save<T>(instance);
    }

    public T LoadById<TKey>(TKey id) where TKey : class
    {
        var query = App.Database.Query<T, TKey>()
                                .Where((table) => table.Key == id)
                                .FirstOrDefault();

        return query.LazyValue.Value ?? default(T);
    }

    public ICollection<T> FindAll<TKey>()
    {
        var items = App.Database.Query<T, TKey>()
                                .Select((table) => table.LazyValue.Value)
                                .ToList<T>();
        return items;
    }
}

In the sample application I use the domain model based on the cargo example used in Eric Evans' book which can be found here

CargoRepository

internal sealed class CargoRepository : 
    SterlingRepository<Cargo>, ICargoRepository
{

    public void Store(Cargo cargo)
    {
        Save(cargo);
    }

    public Cargo Find(TrackingId trackingId)
    {
        return LoadById(trackingId.IdString);
    }

    public ICollection<Cargo> FindAll()
    {
        return FindAll<string>();
    }
}

CargoFactory

internal static class CargoFactory
{
    public static Cargo CreateNew(string origin, string destination)
    {
        // Method implementation can be found in the sample application.
    }
}

Armed with the above classes you can create a Cargo, save it using the CargoRepository and load it. Sterling will save the whole object graph and when you load, it will  defer the creation of the whole object using the Lazy<T> class.

public sealed class CargoPageViewModel : PropertyChangedBase
{
    private readonly ICargoRepository repository;

    public SterlingPageViewModel(ICargoRepository repository)
    {
        this.repository = repository;
    }

    public void StoreAndFind()
    {
        Cargo cargo = CargoFactory.CreateNew("Glyfada", "Perachora");
        this.repository.Store(cargo);

        Cargo saved = this.repository.Find(cargo.TrackingId);

        Debug.Assert(cargo.RouteSpecification.Equals(saved.RouteSpecification));
        Debug.Assert(cargo.Delivery.Equals(saved.Delivery));
        Debug.Assert(cargo.Equals(saved));
    }
}

Your domain model classes can be POCOs. That is, you don't have to inherit from anything in order to persist an instance of a type in the database. It just works!

The documentation can be found here. The sample application can be found here.