A couple of quick links to throw out there
NCover - Code Coverage Tool.
NCoverBrowser - A
tool created by Jeff Key to easily
see your code coverage file.
Michael Swanson has a post about
integrating MSBuild into a Continuous Integration environment
Virtual Cellar
So, I've been busy over the last few days implementing some classes in my
architecture so I really haven't had time to post to my blog. In this post I'll
discuss my implementation. I've been following the Repository discussions put
forth by Steve Maine and
Steve Eichert, as
well as re-reading some sections in
Martin Fowler's PoEAA
book. Incidentally he's been busy
adding further information here.
As you may (or may not recall), I laid out my initial application
architecture in
this
post. I'd like to revisit that architecture in this post and add some
concrete code samples as well. The figure below illustrates my "version 2" of
the Virtual Cellar architecture, and it illustrates what I've currently coded so
far

As you can see there is not much change in the lower data layers, these
classes belong to the Lorengo.VirtualCellar.Data namespace, and use the provider
model for isolating the data storage specific code. In the figure above, the ProducerRepository uses the IProducerDataProvider interface for handling the
CRUD operations on Producer instances. The AccessVirtualCellarDataProvider uses
System.Data.OleDb classes in it's implementation.
The ProducerRepository sets it's IProducerDataProvider _producerDataProvider
member by calling the GetProducerDataProvider method.
_producerDataProvider = (VirtualCellarDataProviderBase.Instance()).GetProducerDataProvider(); |
The GetProducerDataProvider looks at the .config file for the application and
loads the appropriate class (in this case the AccessVirtualCellarDataProvider).
This code was patterned after the model used in .Text
<virtualCellar defaultProvider="AccessVirtualCellarDataProvider" defaultLanguage="en-en" >
<providers>
<clear/>
<add name = "AccessVirtualCellarDataProvider"
type = "Lorengo.VirtualCellar.Data.AccessVirtualCellarDataProvider, Lorengo.VirtualCellar.Data"
connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source=Lorengo.VirtualCellar.DB.Access\VirtualCellar.mdb;"
/>
</providers>
</virtualCellar>
|
The ProducerRepository implements the IRepository interface. Currently
only two methods are defined
public interface IRepository
{
RepositoryItemBase Load( int id );
void Save( RepositoryItemBase ri );
}
|
You'll notice that these methods reference the RepositoryItemBase class,
which all classes wishing to be stored in a repository must inherit from.
Looking at the class diagram you can see that the RepositoryItemBase class
declares two attributes that support <<get>> and <<set>> operations. The "Id"
property which is unique by repository for that specific instance, and the
RepositoryState (I'll have to think of a better name, perhaps ItemState) which
is an enum as defined below.
public enum RepositoryItemState
{
New = 0, // Item is new and not yet stored in the repository
Dirty = 1, // Item has changed since it was last retrieved from the repository
Clean = 2 // Item is unchanged since it was last retrieved from the repository
} |
The RepositoryItemState enum is used by the class implementing the
IRepository interface to determine whether the RepositoryItem should be
created or updated in the repository.
The RepositoryItemBase class allows the setting of these two attributes while
the Producer class uses the c# "new" modifier to provide a new implementation
which prevents this. Only the Repository for this class should be able to modify
these attributes. This scheme only works if the developer of new business domain
classes chooses to add the new implementation, it is not enforced by the design.
A better solution would be to derive a new class from RepositoryItemBase which
already hides the setter and move the Repository classes to their own assembly,
then mark the RepositoryItemBase classes as protected internal to prevent
business domain classes from overriding their behavior, for now however I will
leave these classes as is.
So looking at some inital code for the ProducerRepository.Save()
/// <summary>
/// Saves the Producer to the repository
/// </summary>
/// <param name="ri"></param>
public void Save( RepositoryItemBase ri )
{
Producer p = (Producer)ri;
if( p == null )
{
throw new ArgumentNullException( "Object to save cannot be null." );
}
switch( ri.RepositoryState )
{
case RepositoryItemState.New:
{
ri.Id = this.ProducerDataProvider.Add( p.Name );
ri.RepositoryState = RepositoryItemState.Clean
break;
}
case RepositoryItemState.Dirty:
{
this.ProducerDataProvider.Update( p.Id, p.Name);
ri.RepositoryState = RepositoryItemState.Clean
break;
}
case RepositoryItemState.Clean:
{
// No need to do anything
break;
}
default:
{
break;
}
}
} |
Based on the RepositoryState we call either the Add() or Update method.
Also since we are referencing the RepositoryItemBase class this allows us to
set the .Id for newly created objects and modify the .RepositoryState for
reflecting its Clean state. We also know that since this is a
ProducerRepository we can upcast the ri instance to a Producer instance for
the purpose of retrieving the Producer.Name information.
Now, this code is not perfect, we should be doing a check to make sure we are
indeed getting a Producer object and throw an exception if we did not get one. I
should break out refactor the different cases into their own
private methods, and enclose the calls to the DataProviders in try...catch
blocks to ensure that RepositoryState is updated correctly.
So what would some code look like? Well I've written multiple test cases for
each of these new classes (actually I wrote those first). Here's the Save tests
for the ProducerRepository class.
/// <summary>
/// Tests to make sure a newly created Producer can be saved
/// </summary>
[Test]
public void SaveProducer()
{
Producer p1 = new Producer();
p1.Name = "Hightower Cellars";
_repository.Save( p1 );
Producer p2 = (Producer)_repository.Load( p1.Id );
Assert.IsNotNull( p2 );
Assert.AreEqual( p1.Id, p2.Id );
}
/// <summary>
/// Tests to make sure a null argument exception is thrown
/// for a null producer
/// </summary>
[Test]
[ExpectedException( typeof(ArgumentNullException) )]
public void SaveNullProducer()
{
Producer p = null;
_repository.Save( p );
} |
You'll notice that I explicitly cast the returned value from the Load()
method because the IRepository signatures only return types of
RepositoryItemBase. For this test, I really don't have to do that because I'm
not checking any specific Producer values, but I did anyway. I could also
investigate using the "as"
operator or wait until C# 2.0 and use generics. Another option would be to
perform an
Encapsulate Downcast refactor. So many options!
For this post I just wanted get my first implementation of the design done.
I'll look at adding overloads to the Load and Save methods to deal with
collections, and deal with the problems of multiple aggregate roots. Furthermore
I will want to add some instrumentation to the code.