tags:

views:

88

answers:

3

Imagine you have an entity that has some relations with other entities and you want to load only some of these entities to display them in diferent views.

For example, given this entity:

public class Category
{
     public int id;
     public Category child;
     public Category parent;
}

In the view "ShowChild" you don't want to load the "parent" property since you are not showing it.

So, given this scenario I implemented a very nice "system" in my repository to load entities from DB filling only the properties I want. It works this way:

Category category = repo.FindCategory(id, (int)(LoadLevel.basic | LoadLevel.Child))

So now I have a category instance with only the id and Child properties loaded.

The dilemma I'm facing here is that if I define the LoadLevel in my serviceLayer (where it should be) I'll have to write two methods, "LoadCategoryWithChild" and "LoadCategoryWithParent" in my service class, one for each view (DRY violation?).

public class CategoryService
{
     public Category LoadCategoryWithChild(int id)
     {
         int loadlevel = (int) (LoadLevel.Basic | LoadLevel.Child);
         return repo.FindCategory(id, loadlevel);
     }
}

OR, the other option I see is to define the loadlevel in the controller (MVC violation?) and implement just one method in my service class:

public class CategoryService
{
     public Category LoadCategory(int id, int loadlevel)
     {
         return repo.FindCategory(id, loadlevel);
     }
}

Which option would be better? I think that the DRY violation is much worse since it implies writing a lot of redundant code.

A: 

This is probably the number one problem with Object Relational Mapping. Most ORM solutions get around it by having lazily loaded object properties, such that you only need one loading mechanism which caters to the majority of use cases. The minority function which uses additional properties can lazily load transparently what it needs from the View when its asked for via a proxy.

Personally I am not a fan of either of the solutions above or indeed the third solution of a transparent proxy. The proxy solution however will work more consistently, fail less frequently on minor changes in the View layer and the main impact is normally just a little performance. You can always optimise it when it proves to be a problem.

Hibernate as an example uses this approach, although you have to tell it whether a property is lazy loaded or not. Lazy loading via proxy in Hibernate also can't lazy load in all circumstances as it needs to be within a transaction. These limitations are there for a practical performance reasons. Of the database mapping approaches proxies/lazy loading is the easiest to use but it comes with its own complexities.

Paul Keeble
You will still have to (N)Hiberante when to lazy load and when not.
Paco
Have to tell I mean
Paco
+1  A: 

I definitely prefer the second solution by a long shot. I don't think it is a problem for the controller to give the service class a hint at what data it needs (which, frankly, is the same thing it is doing in the first solution by calling function A instead of function B).

I would change the second parameter to not be an int though and be an enum type so that the caller knows what the valid options are

Erv Walter
A: 

I suggest:

public Category LoadCategory(int id, params LoadLevel[] levels)
{
 int loadLevel = LoadLevel.Basic;

 foreach (var level in levels)
  loadLevel = loadLevel | level;

 return repo.FindCategory(id, loadlevel);
}

Example usage:

LoadCategory(0, LoadLevel.Parent, LoadLevel.Child); // self + parent+ child
LoadCategory(1, LoadLevel.Child); // self + child
LoadCategory(2); // self only
ANaimi