7 Comments My thoughts about IRepository<T> - 01/22/09

As we all know, the blue bible states that we should use repository-classes that provide access to our objects, and that encapsulate the actual CRUD operations performed on the datastore. And if you didn’t know this, it’s time to read Eric Evan’s great Domain-driven Design book.

There’s been a lot of fuzz lately about generic repositories. Is a generic repository the right thing to do? It’s goal is to avoid the duplication of code for common operations, such as the saving and deleting of entities. NHibernate provides an API, that makes it very easy to create a generic IRepository class, that satisfies all the basic needs of any repository we would be implementing. You can see how this is done in Ayende’s Rhino.Commons, and on top of that, Davy wrote a great post that explains the how and the why. Read about it here.

There is only one thing I would change about Davy’s example. I would define the interface like this: IRepository<EntityType, IdType>, instead of IRepository<EntityType>. You’ll see in his example, that the Get operation, uses the object type for the ID. Working with object will work perfectly, but I changed it just in favour of type safety.

What does Evans say about repositories?

Let me quote him exactly (Extract from Chapter 6):

“For each type of object that needs global access, create an object that can provide the illusion of an in-memory collection of all objects of that type. Set up access through a well-known global interface. Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store. Provide methods that select objects based on some criteria and return fully instantiated objects or collections of objects whose attribute values meet the criteria, thereby encapsulating the actual storage and query technology. Provide REPOSITORIES only for AGGREGATE roots that actually need direct access. Keep the client focused on the model, delegating all object storage and access to the REPOSITORIES.”

Just take a second look at whay I put in bold. Every type of object that needs global access, should have it’s own repository. Which means that the generic repository isn’t the way to go, right?
As most of you already know, I’m very passionate about enforcing the DRY principle. If we create a repository for each object we need to crud data for, then we’ll have some code duplication, since the way we get, save and delete our objects with NHibernate, is always the same. And that’s why we introduced IRepository<T>.

The way I see it

Create a repository for each aggregate root you need access to, and expose it’s methods through an interface. I didn’t say you shouldn’t be using the IRepository, though. I’m just saying to not expose it to your clients. Let them deal only with your specific repositories.

Give me some code, please…

Define your IRepository interface, and implement it in a Repository class. Define an interface per specific repository, and implement it. It’s the specific repository’s implementation that will be accessing the generic Repository class.

The client will only access IUserRepository directly.

public interface IUserRepository
{
	/// <summary>
	/// Retrieves a User by his e-mail address
	/// </summary>
	/// <param name="email">The User's e-mail address</param>
	/// <returns></returns>
	User GetByEmail(string email);
}

public class UserRepository : Repository<User, Guid>, IUserRepository
{
	/// <summary>
	/// Retrieves a User by his e-mail address
	/// </summary>
	/// <param name="email">The User's e-mail address</param>
	/// <returns></returns>
	public User GetByEmail(string email)
	{
		var criteria = DetachedCriteria
			.For<User>()
			.Add(Expression.Eq("Email", email));

		return base.FindOne(criteria);
	}
}

The way the client’s will use the repository, is obvious:

IUserRepository userRepository = new UserRepository();
userRepository.GetByEmail("me@noctovis.net");

As you can see, the code remains clean, readable, short and you’re not repeating any code. If you’re doing basic Save and Delete operations, you’ll have write methods that just wrap the generic Repository’s methods, but still, you won’t have code duplication.

Why I don’t want to expose IRepository<T> directly to clients

There are a few downsides to exposing IRepository<T> to your clients.

1) NHibernate’s Criteria API will be exposed to all your clients. The Repository pattern’s goal is to encapsulate the way you do your data-access. If you offer IRepository to your clients, they are going to have to construct Criteria objects to query what they want. So, again, you’re forcing them to know how the Criteria API works, which conflicts with the goal of a repository.

2) You gain more flexibility. How? Well, if the client would use IRepository directly, he would have to deal with a lot more stuff.

Let me give you an example. Imagine, that it’s a requirement to not actually delete your entities from the database when a user clicks ‘Delete’. You only have to set the entity’s Active-bit to false, and set the ChangedOn and ChangedBy properties. When using IRepository<T> directly, this responsibility shifts towards the client. That’s not good. If you use a custom repository, you can have this handled by UserRepository (from my example above), and have the UserRepository’s delete method, adjust the properties you want, and call the Save-method. Your client doesn’t have to know about this. In his little world, he deleted an entity, and that’s it.

The consequence is again, flexibity. If one day, the product owner says that it’s unnecessary to save deleted Product-entities, you can change your ProductRepository class, make it actually delete your products, without affecting any client-code.

This is just an example, I could come up with more scenario’s where this way of working would be interesting. Just imagine you need to validate entities before saving them to the datastore, or if you need to track changes and store every change a user makes in a seperate datastore…

Note, that it’s not my intention to make you put all the logic to do validation, change tracking, or whatever other requirements you have, in your specific repository classes. If you need to do validation, have that handled by a Specification, and if you need to track changes, have that handled by a different class too. Conclusion: never forget to apply SRP!

3 Comments Fluent nHibernate: Classic mapping - 01/14/09

As I mentioned in my previous post, Fluent NHibernate offers two different ways to realize your mappings in C# code:

  • - adding a Map-class per entity and write out the mapping in C#
  • - use the Automapping feature in Fluent NHibernate and let the framework do all the work for you
  • In this post I’ll show you how you can write a basic mapping of an entity using a ClassMap.

A simple example

I’m starting out with a very simple example, with just one entity and a value object. I’ll be extending this tiny domain a bit, step by step (probably in another post).

fluentmodel

In my DB, I just have one table, Person. It contains all the address-data, but in my domain, I want to map that data into a seperate object, a value object. If you were using NHibernate, you could do just that using the “component”-tag in ugly XML.

Using classic mapping, you create a new class, PersonMap, which should derive from the generic class, ClassMap.

Here’s the code:

public class PersonMap : ClassMap<Person>
{
	public PersonMap()
	{
		Id(x => x.PersonId);
		Map(x => x.FirstName);
		Map(x => x.LastName);
		Map(x => x.PhoneNumber); 

		Component<Address>(x => x.Address, m =>
		{
			m.Map(x => x.Street);
			m.Map(x => x.Number);
			m.Map(x => x.ZipCode);
			m.Map(x => x.City);
			m.Map(x => x.Country);
		});
	}
}

If you want to specify the length of the FirstName property as in your database, or constraint the property to never allow NULL, you can do this as follows:

 Map(x => x.FirstName)
   .CanNotBeNull()
   .WithLengthOf(100);

I mentioned in my introduction post that FNH also gives you the ability to code by convention. It states that a developer should only specify the items that don’t fit within the default behaviour, thus to limit the configuration to a minimum. This makes your code easily maintanable since you don’t have configuration code in which you can get lost, you only have what you need.

Let me demonstrate that with an example. Check out how I mapped my Id property in the ClassMap. Notice I didn’t specify anything at all? Well, that’s because FNH assumes you’re using the identity generator. If you’re not, you can override this by specifying another generator type for your ID. Thus, you will only need to specify how you’ll be generating your ID’s if your not using identity.

Why? This avoids a lot of setup code when all your ID’s use this generator, don’t you think? Still, the flexibility remains. If you want to use another generator type, or explicitly state you are using the identity generator, you can still do so.

New way of testing

First of all, just a note. When I’m playing around with something new, just as now I’m playing around with FNH, I almost never write an application that actually does something. I’m just adding unittests to check if what i’m doing works.

FNH introduces a new way of testing your mappings. Remember how we used to create integration tests that add data to the database, retrieve it afterwards to check if it was successfully inserted? Remember how it was frustrating to notice in those tests that you messed up your NH mapping?

Actually, this was my way of testing if I did my mappings right. If any CRUD-operation failed, it was almost abvious I messed up my mapping somewhere. We have a test “CanAddPerson” which is also responsible to check if your mappings our correct. That’s not good, but there wasn’t another way…

Well, now you can separate the testing of your mappings, and your actual integration tests.

Here’s how you test your mappings:

[TestMethod]
public void CheckPersonMappingIsValid()
{
	new PersistenceSpecification<Person>(new SessionSource(new TestModel()))
		.CheckProperty(x => x.FirstName, "Laila")
		.CheckProperty(x => x.LastName, "Bougria")
		.CheckProperty(x => x.PhoneNumber, "0498123456")
		.CheckProperty(x => x.Address, new Address("My street", "34", "BE-2000", "Antwerp", "Belgium"))
		.VerifyTheMappings();
}

And here’s the integration test which only has the responsibility to check whether we can add Person’s to the datastore or not.

[TestMethod]
public void CanAddPerson()
{
	Person personToAdd = new Person()
							 {
								 Address = new Address("street", "15A", "BE-2100", "city", "country"),
								 FirstName = "Laila",
								 LastName = "Bougria",
								 PhoneNumber = "0497123456"
							 };

	Session.Save(personToAdd);
	Session.Flush();
	Session.Clear();

	// use session to try to load the person
	var fromDb = Session.Get<Person>(personToAdd.PersonId);

	// Test that the person was successfully inserted
	Assert.IsNotNull(fromDb);
	Assert.AreNotSame(personToAdd, fromDb);
	Assert.AreEqual(personToAdd.Address, fromDb.Address);
	Assert.AreEqual(personToAdd.FirstName, fromDb.FirstName);
	Assert.AreEqual(personToAdd.LastName, fromDb.LastName);
	Assert.AreEqual(personToAdd.PhoneNumber, fromDb.PhoneNumber);
}

I ran the tests, and they both pass, so that’s great!

A note about value objects and fluent nHibernate

In my Person example, I’m mapping the address-data with a value object. In the model you’ll see it implements IEquatable.
Of course it does, you’ll think, it’s a value object! I just want to warn you, that if you think “I’ll implement the interface later…” and you run the mapping test, it wil fail. The VerifyMappings method will be comparing the Address instance and will expect true if all the properties match. If you didn’t implement the interface yet, your test will fail.

3 Comments Fluent nHibernate - 01/14/09

I know of many developers that dislike nHibernate just because of the configuration it needs. Come on, it’s not that bad! It’s just a block to add in your config file and a mapping per entity you’ll be using…

Well, it is true that it’s not a lot of fun to create and maintain these mapping files (who likes the ugly XML?).

Everyone of us has -at least- one time:

  • - forgot to mark the mapping file as embedded resource
  • - forgot to update the mapping when renaming a property

And the most annoying thing of all, is that you can only notice such errors at runtime… But we all just keep up with that because of the sweetness nHibernate brings afterwards!

Even the use of MyGeneration, to generate mapping files based on the database, isn’t a final solution for the mapping files issue. It’s not rare that the database changes physically during development, which would mean you need to regenerate the mapping files each time. At that point, generating the database from the mapping files looks like a great option, but then the manual writing of mapping files comes into the picture again.

Conclusion: It can be a pain to set up nHibernate’s configuration.

 

Enter fluent nHibernate.

Imagine using a fluent API instead of ugly XML to write your mappings? Wouldn’t that be great?

Well, thanks to Jeremy Miller and James Gregory and of course all other contributors, you now can find the project on Google Code!

Fluent NHibernate solves several problems:

  • - Changes won’t make our mappings break, just Ctrl+R+R! (that is if you’re using Resharper, but I’m just assuming you do :-) )
  • - No XML is required to write the mappings, only C#
  • - We can actually test the mappings on their own
  • - FH allows us to code by convention

Fluent NHibernate solves the mapping problem in two different ways:

  • - use a Map-class to manually write the mapping of your entities (=> a Map class per entity)
  • - using the Automapping feature of fluent NHibernate

I will demonstrate both ways in upcoming posts. Otherwise I’ll create a post here that’s too long to read.

I’m sure the “i-don’t-use-nhibernate-because-of-the-mappings”-guys, won’t have any reasons to object anymore after I show you how this is done!

|