views:

238

answers:

3

Hi,

I'm porting our old Active-Record based API over to a new structure to make unit testing easier etc. We are using the repository pattern for our data access and StructureMap for dependency injection.

I'm struggling a little now with how to structure everything. Using our 'Product' class as an example, we previously had our model, repository and factory parts all built into the product object, for example to load, edit and save a product we could something like (simplified):-

Dim p As New Product
If(p.Load(1))
   p.Name = "New Name"
   p.Save()
End If

And to get a collection of objects we had a Shared(static) method on the object which acted as a basic factory

Dim arrProds = Product.GetProducts()

After looking at a few examples, in our new structure we now have an IProductRepository, IProductService (which is the factory) and Product model class. So, something like this

Dim prodSvc = ObjectFactory.GetInstance(Of IProductService)
Dim prod = prodSvc.GetProduct(1) //Prod is an Instance of 'Product'
prod.Name = "New Name"
prodSvc.Save(prod)

However, the Product class has the ability to load related data, for example

Dim arrRelatedProds = prod.RelatedProducts

Which inside the Product class looks like this

Class Product
    Function RelatedProducts() As IList(Of Product)
        // prodSvc is an instance of IProductService which is passed into the 
        // Product class in the constructor (or via Dependency Injection)
        Return Me.prodSvc.GetRelatedProducts(Me.ProductID)
    End Function
End Class

I don't like this because it's difficult to test and because I don't like the fact that my 'Model' class (Product) calls the IProductService class directly.

Does anyone have any suggestions about a better way to structure all this?

Cheers

James

EDIT Probably the wrong time of year to ask this! Is there any clarification I can add to make this question answerable??

+1  A: 

I don't know if it's better or worse, but one way to structure it is to get rid of all smartness from your entity/data transfer object Product, and put everything including Create, Retreive, RetreiveAll, Save, GetRelatedProducts, etc. into IProductService. It would make your Product code simpler, and you don't have to worry which class does what.

eed3si9n
+1  A: 

When using the repository pattern instead of active record, don't reference to the repository in the domain object (product). It's not impossible, but you save yourself a lot of trouble when you don't. The best thing you can do is using an ORM that supports lazy loading. Personally I use NHibernate for that. Make your repository dependent on your domain objects, but the domain objects independent of the repository. The best thing to do is not to inject anything at all in your domain objects.

Paco
A: 

@Paco: So in my example above, how would the related products be found? Would I need to load them all when the product object is first populated? I appreciate that using lazy lists would only load them on demand but I'm confused what the code would look like for this. Maybe you could point me towards an example (using NHibernate or whatever) where this is done?

Many thanks

James
When you use NHibernate, you create mapping files to sync your domain objects with your database. That can be XML files or code with fluent NHibernate. When your interested in NHibernate, I must warn you there is a learning curve. A good source to start is summerofnhibernate.com
Paco
You can probably lazy load without using any orm, but I need to know more about your specific implementation to post a code example.
Paco