chris carter's web log

Home |  Contact |  Admin
 

IRepository

Posted on August 4, 2008

As I'm testing features of ASP.NET MVC, I'm noticing that it would  be really nice to be able perform non-persistent CRUD operations on POCO's.  Meaning, i need data, i need objects, but I don't want to set up a test database for these tests. I need to be able to create a class, and then create lists of instances of that class, and then add new ones, edit existing ones, delete some, exactly the same stuff I'd normally do, just no database. 

I searched on "IRepository" and came back with awesome examples, most of which enabled you to do almost if not everything you would need to do in your app, many of which I'll be revisiting.  But I couldn't find one that did almost nothing.  So I wrote one.  And it does...well, almost nothing.

Here is my initial version of IRepository:

public interface IRepository<TModel>
			where TModel : IModel, new()

	TModel Find(int id);
	IEnumerable<TModel> FindAll();
	void Save(TModel model);
	void Delete(TModel model);
	int Count { get; }
}
1
2
3
4
5
6
7
8
9

It's pretty simple, and does only the bare minimum.  Every class that wants to participate in a repository must implement IModel, this tells the repository that anything in it is guaranteed to have an int ID property, by which it can query:

 
public interface IModel{
	int ID { get; set; }
}
1
2
3

Let's say you create a class, Customer.  In order to enable it to be usable in a repository, it needs to implement IModel, so the class might look something like this:

public class Customer : IModel {

  public int ID { get; set; } //required by IModel

  public string FirstName{ get; set; }

  public string LastName{ get; set; }

}
1
2
3
4
5
6
7
8
9

Using the repository is simple,

//first create a customer repository
IRepository<Customer> repo = new Repository<Customer>();

//now add some customers
repo.Save(new Customer() { FirstName = "Chris", LastName = "Carter" });
repo.Save(new Customer() { FirstName = "Emmitt", LastName = "Carter" });

//make sure they are in there
Assert.AreEqual(2, repo.Count);
Assert.AreEqual("Emmitt", repo.Find(2).FirstName);

//let's remove one
repo.Delete(repo.Find(2));

//make sure it's gone
Assert.AreEqual(1, repo.Count);
Assert.IsNull(repo.Find(2));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

I bundled up the code in a project inspired by Rhino Commons called EPS.Common, the source is here: http://svn.chrisjcarter.com/public/EPS.  I have a sample ASP.NET MVC(Preview 4) solution available for download here(less than 100k).

Comments

Tobin Harris

Having a generic in-memory repository looks pretty cool. Thanks for posting the code. I don't quite understand what happends when you want to start building complex queries? Also, what are your plans for when you want to start using a database? I wonder if there's some way of using LINQ that would work against the in-memory object model for testing, and also against the database when you implement the DB repository? Not sure how realistic it is, but you could then have one set of queries that work against both repository implementations. Currently I'm using Rhino with SQLite for testing, which makes for faster test runs. I still notice a lag as the database is initialised though.

Chris

I started thinkin about how to [easily] bridge that gap between messing around with the in-memory thing, and then flipping a switch to turn on the real deal that hits the database; LINQ seems like the obvious choice, but I don't know if that gets me too far away from the goal of just having some simple object lists with a little functionality so I can play with the MVC UI bits. Like, the FindAll method in my example is sort of stupid because it always returns everything, I was toying with the idea of adding some parameters that would take a LINQ where and/or orderby clause, and whatever else might be of use but then I'd have to figure out how to bridge the gap from LINQ to ActiveRecord. I've seen some people around the net with some experiments, but nothing mainstream. Maybe it's time to make the jump to raw NHibernate and hit the LINQ to NHibernate bandwagon?

Tobin Harris

If you want to play with MVC quickly with low overhead, then yeah I'd use ActiveRecord with a real database. Because AR/NH can gen the database for you, you can very quickly change things without friction. I usually have a script that sets up my dev database by: a) drop/recreating the db (easily done with AR or NH), b) creates all lookup/system data as entities using AR/NH, c) creates some example entities objects and saves them to the db. I haven't looked at LINQ to NHibernate yet, but it's tempting :)

Post a Comment

(required)
(required)
(no HTML!)