Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

In almost every project I work on with a team, the same problem seems to creep in. Someone writes UI code that needs data and writes a data access method:

AssetDto GetAssetById(int assetId)

A week later someone else is working on another part of the application and also needs an AssetDto but now including 'approvers' and writes the following:

AssetDto GetAssetWithApproversById(int assetId)

A month later someone needs an asset but now including the 'questions' (or the 'owners' or the 'running requests', etc):

AssetDto GetAssetWithQuestionsById(int assetId)
AssetDto GetAssetWithOwnersById(int assetId)
AssetDto GetAssetWithRunningRequestsById(int assetId)

And it gets even worse when methods like GetAssetWithOwnerAndQuestionsById start to appear.

You see the pattern that emerges: an object is attached to a large object graph and you need different parts of this graph in different locations.

Of course, I'd like to prevent having a large number of methods that do almost the same. Is it simply a matter of team discipline or is there some pattern I can use to prevent this? In some cases it might make sense to have separate methods, i.e. getting an asset with running requests may be expensive so I do not want to include these all the time. How to handle such cases?

share|improve this question
1  
You can use something like grails that handles lazy loading (gorm via hibernate) of properties - when access is attempted. This way, you just need to call a = getAssetById(x) and then can call a.questions etc.. without specifically loading them as the underlying ORM system loads it for you when the access is attempted. –  techfoobar Sep 27 '12 at 7:28
1  
That would be possible but requires you to keep some database context open while querying. I'd rather not have this kind of knowledge leaking out of the data access layer. And you have less control over queries that are executed. But a very interesting option... –  Ronald Wildenberg Sep 27 '12 at 7:43
    
Yeah and that the whole point of separating it out in DTOs I guess. Grails goes for the non-DTO way of doing things.. –  techfoobar Sep 27 '12 at 7:45
    
Running open ended queries from a single interface would require that interface to be a domain specific query language. The accepted answer is similar to that. –  mike30 Sep 28 '12 at 13:46

4 Answers 4

up vote 4 down vote accepted

Syntax-wise, I'd create an intermediate query-building object with a fluid interface:

// all the basic, cheap to query fields
AssetDto a = AssetRetriever(asset_id).fetch() 

// some common expensive fields
AssetDto a = AssetRetriever(asset_id).withOwner().withQuestion().fetch() 

// numerous less common fields may not command dedicated methods
AssetDto a = AssetRetriever(asset_id).withFields("foo", "bar").fetch() 

// Better yet, use an enum and enjoy static checking
AssetDto a = AssetRetriever(asset_id).withFields(F_OWNER, F_QUESTION).fetch() 

I hope it's obvious enough to implement. The only method that will actually touch the database is fetch().

share|improve this answer
    
I really like this solution. It enforces what I want to achieve with a comprehensible and clean syntax and it gives lots of possibilities for extension of the interface and optimization of SQL queries. –  Ronald Wildenberg Sep 28 '12 at 7:37

When dealing with large object, this is really common. While adding new methods increases performance, it significantly decreases the maintainability. And again you need to choose between those two.

I suggest you have a method that returns (not necessarily the smallest) commonly used data, another that returns the whole object, and probably a few more for the most expensive resources.

Another approach is to have methods that return only the necessary fields of the object, like AssetQuestions GetAssetQuestionsById(int assetId) or Owners GetAssetOwnersById(int assetId).

Along with this you need to establish some rules regarding retrieving data. For example, if someone needs 5 fields of the object, and there is an existing method returning 8, the existing method should be used.

share|improve this answer
    
I hoped there would be some pattern I could enforce so that the problem wouldn't occur but I'm afraid your solution is best. It comes down to more discipline and research when you write new data access code. –  Ronald Wildenberg Sep 27 '12 at 14:49
    
I like your solution that introduces additional methods for retrieving related objects. It may cost a little performance since you no longer JOIN data in the database but for maintainability it's probably a large improvement. –  Ronald Wildenberg Sep 27 '12 at 14:51
3  
There is one "crazy" solution that comes to my mind: create a type with a boolean field for each parameter, set true for the fields you want to retrieve and pass that object as a parameter ))) –  superM Sep 27 '12 at 14:51
    
That passed my mind also and the only disadvantage is that you have to be prepared to take all possible combinations into account in your data access code. Although you could of course write very efficient queries for the most common cases... –  Ronald Wildenberg Sep 27 '12 at 14:57
    
I guess that would be difficult to maintain too, but might work in some cases –  superM Sep 27 '12 at 14:59

I've been through this same problem recently and adopted the following solution:

Data access methods should get data only from a single resource (e.g., database table), and if the process needs related objects appended to the main object it should call for the method responsible for those respective objects.

This way if you need an asset with it's approvers you should create a facade method wich join the objects.

Example:

public Class AssetFacade {

   public AssetDto getAssetWithQuestionsByAssetId(int assetId) { 

      AssetDto asset = AssetDao.getAssetById(assetId);
      List<QuestionDto> questions = AssetDao.getQuestionsByAssetId(assetId);
      asset.setQuestions(questions);

      return asset;
   };
 }
share|improve this answer
1  
This is a possible solution but I don't like that you lose all possibilities for optimizing data access through the database. I.e. one query with a join on three tables may be faster than three separate queries. –  Ronald Wildenberg Sep 28 '12 at 8:04
    
Agree with you, but couldn't find a better solution at that time. Glad you created this question for me to learn a better way too! –  marcioggs Sep 28 '12 at 21:16

Is it simply a matter of team discipline or is there some pattern I can use to prevent this?

Yes, it is a matter of some guidelines in naming pattern for the team. You may set simple 4 methods like GetEntityById(), GetAllEntities(), SetEntity(), DeleteEntityById().

In addition, you may have two dto's with the naming AssetSimpleDto GetAssetById(assetId) and another detailed dto called as AssetDto GetAssetDetailById(assetId) . The first method and dto is customized to bring bare minimum , while second is bringing all related information that your functionality may need.

share|improve this answer
    
Unfortunately the case is not as easy as 'get simple' or 'get all' so this does not really solve the underlying problem. This would probably cause everyone to use the 'get all' method because they need a part of the object graph that is not returned by 'get simple'. –  Ronald Wildenberg Sep 27 '12 at 14:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.