Announcement Announcement Module
Collapse
No announcement yet.
DAO Reference Inside an Entity Domain Object? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • DAO Reference Inside an Entity Domain Object?

    I have an entity domain object that has a large collection of child entity domain objects. I have to implement an operation (let's call the operation getSum) for the parent that involves filtering out most of the child objects and then summing a field in the remaining objects and returning the sum.

    The database could hold hundreds of thousands of the child objects but for any single invocation of this operation, we are usually only interested in a small percentage of those child objects. Therefore, rather than loading all of the child objects into memory (in a Collection that lives in the parent) and filtering them there, I think it would be better (performance wise) to filter them on the database server. So, I have created an operation in a DAO that submits a datbase query that does this filtering and the calculate the sum.

    For layering purposes, I do not want to give the client direct access to the DAO. Instead, the client will call getSum on some object and that object will then delegate to the DAO. So, my question is, WHICH object should expose getSum to the client? Should it be the parent object or some service object? For example:

    Should I do this?
    Code:
    class MyParentEntity
    {
      private MyDao dao;
      
      public void setDao(MyDao dao)
      {
        this.dao = dao;
      }
    
      public int getSum(FilteringParams params)
      {
        return dao.getSum(params, this);
      }   
    
      // other operations
    }
    OR this?
    Code:
    class MyServiceImpl implements MyService
    {
      private MyDao dao;
      
      public void setDao(MyDao dao)
      {
        this.dao = dao;
      }
    
      public int getSum(FilteringParams params, MyParentEntity parentEntity)
      {
        return dao.getSum(params, parentEntity);
      }   
    
      // other operations
    }
    In this first case, the client will call MyParentEntity.getSum(). In the second case, the client would instead call MyService.getSum(), passing an instance of MyParentEntity as a parameter.

    Putting the operation into MyParentEntity seems more natural because the operation involves an instance of MyParentEntity. On the other hand, it seems unnatural to give an entity object access to a DAO.

    Any advice?

  • #2
    I have also been exploring (and justifying) the first approach, because having to go through a service API to get child DOs of a parent DO will almost unavoidably lead to an anemic domain model.

    Comment


    • #3
      manifoldronin, thanks for your reply. It's nice to know that I am not the only one wrestling with this issue. So I guess I'm not a dummy after all...

      Now, correct me if I'm wrong...from my reading of Spring books, sample code, documentation and forum topics, I get the feeling that many Spring folk usually would use the service to get the child domain objects. Why do they seem to prefer the service approach?

      I recently got the idea for the first approach (i.e. giving a DAO reference to the parent) from the book Domain-Driven Design by Eric Evans, who is apparently a colleague of Martin Fowler. Specifically, the idea came from pages 177-178, where he talks about refactoring a child collection into a query.

      It seems to me that your comment about "anemic domain model" caused by using the service is bang on. In fact, Fowler talks about the AnemicDomainModel anti-pattern on his website. His comments seem to describe the situation here.

      One thing I do like about the service approach is that it makes it very easy to see where transactions are demarcated. If I put some DAO access into domain objects, will I have to sprinkle transactional demarcation all over the place? If so, is this a bad idea? In other words, is there anything wrong with making a method in a domain object transactional?

      By the way, I HIGHLY recommend the aforementioned book. In particular, I found Evans notion of Aggregates to be particularly helpful.

      Comment


      • #4
        Originally posted by cyboc
        manifoldronin, thanks for your reply. It's nice to know that I am not the only one wrestling with this issue. So I guess I'm not a dummy after all...
        Same feeling here... (but then, it's still fairly suspicious that only the two of us are talking about this idea here... :wink:
        Originally posted by cyboc
        Now, correct me if I'm wrong...from my reading of Spring books, sample code, documentation and forum topics, I get the feeling that many Spring folk usually would use the service to get the child domain objects. Why do they seem to prefer the service approach?
        I can think of a few arguments for the service approach(and counter arguments respectively):

        - As you said, it's easier to see the transaction boundary. But I think it's a myth, because a service method does not necessarily represent the corresponding transaction boundary. It's all up to the transaction declaration outside the service method. It's no easier nor harder to tell the transaction boundary when doing the logic from within the domain objects.

        - Domain objects should not know about external interfaces such as DAO's. I agree in principle, but DAO's should not be considered external, because they are abstract interfaces you define and have total control over.

        - Performance concerns and implementation issues, i.e., domain objects are usually instantiated by an ORM tool (hibernate for example), so how and when to inject the DAO could be a problem. Also, a DAO being stateless would be a waste of memory to be injected into each domain object. I think these are valid concerns and have been looking into using AOP to solve these problems.

        Originally posted by cyboc
        I recently got the idea for the first approach (i.e. giving a DAO reference to the parent) from the book Domain-Driven Design by Eric Evans, who is apparently a colleague of Martin Fowler. Specifically, the idea came from pages 177-178, where he talks about refactoring a child collection into a query.

        It seems to me that your comment about "anemic domain model" caused by using the service is bang on. In fact, Fowler talks about the AnemicDomainModel anti-pattern on his website. His comments seem to describe the situation here.
        Yes, that is the very source where my thoughts came from, too.

        Comment


        • #5
          Well I am thinking of it too, but...

          The fundamental question is whether you consider your "domain object loader" (your DAO) as part of the domain object, and I don't think it is.

          The DAO itself is a service, so I don't think it should live in the domain object.

          The domain model is not aneamic just because it requires collaborators. It is perfectly OK to pass collaborators at runtime, so you would have

          public int getSum(ChildEntityLocatorStrategy, FilteringParams)

          where ChildEntityLocatorStrategy was an interface which retrieved the relevant entities. Of course, there would be a DAOChildEntityLocatorStrategy which simply called dao.getSum(params, parent).

          Comment


          • #6
            yatesco,

            Thanks for your comments. Just to clarify, is this how you see the code?
            Code:
            class MyParentEntity
            {
              public int getSum(ChildEntityLocatorStrategy childLocator, FilteringParams params)
              {
                childLocator.getSum(params, this);
              }
            
              // other operations
            }
            
            interface ChildEntityLocatorStrategy
            {
              public int getSum(FilteringParams params, MyParentEntity parentEntity);
            }
            
            class DAOChildEntityLocatorStrategy implements ChildEntityLocatorStrategy
            {
              private MyDao dao;
             
              public void setDao(MyDao dao)
              {
                this.dao = dao;
              }
            
              public int getSum(FilteringParams params, MyParentEntity parentEntity)
              {
                return dao.getSum(params, parentEntity);
              }   
            
              // other operations
            }

            Comment


            • #7
              Originally posted by manifoldronin
              domain objects are usually instantiated by an ORM tool (hibernate for example), so how and when to inject the DAO could be a problem. Also, a DAO being stateless would be a waste of memory to be injected into each domain object. I think these are valid concerns and have been looking into using AOP to solve these problems.
              Yatesco's idea seems to solve the problem of how to inject the child loader collaborator (either a dao or his strategy object) into the parent domain object -- he does it with each invocation of getSum. While this is not as transparent as getting the IOC container to inject it when the domain object is instantiated, it does work in the situation where Hibernate (instead of the IOC container) manages the domain object. Having said that, the AOP idea would be nice if you can get it to work with Hibernate-managed domain objects.

              Comment


              • #8
                Yatesco's approach is definitely valid. However here's what I don't like it about.

                It forces the consumer of the domain object to worry about providing a strategy to retrieve part of the domain object which should have been the domain object's own concern. E.g., in a typical parent/child situtation, the domain object Parent should provide a simple JavaBean getter method, getChildren(), which returns all the children. Or the Parent could choose to provide getChildIterator() for more efficient operations. Either way, how the children are retrieved is not of the caller's concern.

                As already implied, it would also break the JavaBean convention and encapsulation. Now a domain object would have two different kinds of getters for different kinds of properties - one for those simple properties, and another for those requiring complex handling.

                Last but not the least, passing a strategy in each call may be an overkill in most cases, because this strategy rarely changes at runtime.

                Comment


                • #9
                  manifoldronin -- good points.

                  yatesco -- rebuttal?

                  (btw, good discussion, isn't it?)

                  Comment


                  • #10
                    Are any of the heavyweights (e.g. Rod and Colin) going to chime in on this discussion?

                    Comment


                    • #11
                      Originally posted by cyboc
                      Are any of the heavyweights (e.g. Rod and Colin) going to chime in on this discussion?
                      They tend to get real quiet on this point. It underscores a weakness of the framework; namely, it is sometimes difficult to perform injection on domain objects.

                      Ben goes so far as to suggest that allowing a domain object to reference another Spring service is bad design. I respectfully disagree with that view.

                      In http://forum.springframework.org/showthread.php?t=9846, Rod offers a solution for hydrating Hibernate objects, but it is only halfway implemented, and a final implementation is not scheduled until Spring 1.4.

                      I know it's not an easy problem to solve, but I wish it was a higher priority issue.
                      Last edited by robyn; May 16th, 2006, 04:18 AM.

                      Comment


                      • #12
                        Originally posted by cepage
                        In http://forum.springframework.org/showthread.php?t=9846, Rod offers a solution for hydrating Hibernate objects, but it is only halfway implemented, and a final implementation is not scheduled until Spring 1.4.
                        As far as I tried it, it works with no problems whatsoever.
                        Last edited by robyn; May 16th, 2006, 04:17 AM.

                        Comment


                        • #13
                          I think as previously stated, one of the biggest hurdles is the injection of run time services.

                          One of the important points to consider is what is actually going to happen with your domain object. If it will ever be serialized and de-serialized in another environment (replication, webflow-flow scope) then you *really* do not want to keep a handle on the dao.

                          I do not have a *nice* solution for this, and yes it would be really nice if there was a way of having all these things transparently injected for you.

                          BTW; I would still consider using an interface because it seems the child loading strategy isn't an inherent part of the parent.

                          If you *do* want magic injection (which again, I would think very carefully about) then you can always have an interface:

                          HibernateAware {
                          setSession(final Session session);
                          }

                          and have a HibernateInterceptor applied to every hibernate backed object .

                          What would be *really* nice is if we could get spring to load the hibernate objects for us and apply dependency injection, i.e. if the object you got out of hibernate was actually a spring proxy which did nothing other than dependency injection. Of course this isn't possible but hey

                          Comment


                          • #14
                            Originally posted by yatesco
                            I think as previously stated, one of the biggest hurdles is the injection of run time services.

                            One of the important points to consider is what is actually going to happen with your domain object. If it will ever be serialized and de-serialized in another environment (replication, webflow-flow scope) then you *really* do not want to keep a handle on the dao.

                            I do not have a *nice* solution for this, and yes it would be really nice if there was a way of having all these things transparently injected for you.

                            BTW; I would still consider using an interface because it seems the child loading strategy isn't an inherent part of the parent.

                            If you *do* want magic injection (which again, I would think very carefully about) then you can always have an interface:

                            HibernateAware {
                            setSession(final Session session);
                            }

                            and have a HibernateInterceptor applied to every hibernate backed object .

                            What would be *really* nice is if we could get spring to load the hibernate objects for us and apply dependency injection, i.e. if the object you got out of hibernate was actually a spring proxy which did nothing other than dependency injection. Of course this isn't possible but hey
                            This is exactly what DependencyInjectionInterceptorFactoryBean does.
                            Serialization/deserialization problem can be partially solved by using "transient".

                            Comment


                            • #15
                              Originally posted by dejanp
                              As far as I tried it, it works with no problems whatsoever.
                              It only works with Hibernate2, and it only works with a couple of methods, like session.load(). Using methods like query.list() or creating an object in Hibernate do nothing, and you need to inject yourself.

                              I believe that Rod is, correctly, taking a step back and trying to figure out a more holistic approach to this problem than playing whack-a-mole with Hibernate API's.

                              Comment

                              Working...
                              X