Is it good practice to determine what data to load into the controller?

Imagine that you have an object that has some relationship with other objects, and you only want to load some of those objects in order to display them in different views.

For example, given object:

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

      

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

So with this scenario in mind, I have implemented a very nice "system" in my repository to load objects from the DB, populating only the properties I want. It works like this:

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

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

The dilemma I am facing is that if I define LoadLevel in my Service Layer (where it should be), I have to write two methods, LoadCategoryWithChild and LoadCategoryWithParent, in my service class, one for each (DRY violation?) ...

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

      

OR, another option I see is to define the load level in the controller (MVC violation?) And implement only one method in my service class:

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

      

Which option is better? I find DRY violation much worse because it involves writing a lot of redundant code.

+1


a source to share


3 answers


I definitely prefer the second solution with a long shot. I don't think it would be difficult for the dispatcher to give the service class a hint of what data it needs (which, frankly, is the same as in the first solution, calling function A instead of function B).



I would change the second parameter to not be an int, but to be an enum type so that the caller knows the parameters are valid

+1


a source


This is probably the number one problem with object relational mapping. Most ORM solutions wrap around having lazy loaded object properties, so you only need one loading mechanism that works for most use cases. A minority function that uses additional properties can lazily load transparently what it needs from a view when requested through a proxy.

Personally, I am not a fan of any of the solutions above or even the third transparent proxy solution. The proxy solution, however, will run more consistently, less frequently with minor changes to the View layer, and the main impact is usually low performance. You can always optimize it when it turns out to be a problem.



Hibernate uses this approach as an example, although you have to tell if a property is lazy or not. Lazy loading through a proxy in Hibernate also cannot be lazy on loading under any circumstance as it must be in a transaction. These limitations exist for practical reasons. Of the database mapping approaches, proxy / lazy loading is the easiest to use, but it has its own complexities.

0


a source


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);
}

      

Usage example:

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

      

0


a source







All Articles