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

  • #46
    Originally posted by oliverhutchison
    As long as you services layer is defined with an interface there's nothing to fear.
    I buy into this, but like I said all the reading material suggest otherwise. It does seem odd though because the service layer is generally much more coarse grained than the domain object so by using this strategy you are often put into the position of giving your domain object more power than they should have and i really don't think i should have to go making little interfaces for everytime my domain object needs access to a getter like this from the service layer. There must be another alternative.

    Comment


    • #47
      Originally posted by wexwarez
      If you use a service layer I see problems
      1)It seems much more natural to ask the parent object
      I agree. Indeed it does seem more natural to ask the parent object for the children. As you point out, to do this efficiently, the parent object must be injected with a service dependency and then delegate to this service when asked for the children (as you point out, you can optionally cache the children returned by the service).

      The issue, as discussed ad nauseam in this thread, is HOW to inject this dependency into the parent object when the lifecycle of the parent object is managed by Hibernate. Numerous options have been suggested (e.g. DependencyInjectionInterceptorFactoryBean, yatesco's ChildEntityLocatorStrategy, etc). I really like the potential of DependencyInjectionInterceptorFactoryBean but I'm going to wait until it's moved from the sandbox into the main project source tree.

      For now I'm using a solution similar to yatesco's ChildEntityLocatorStrategy. It may not be as elegant as DependencyInjectionInterceptorFactoryBean but it seems to work. Note that I am only using this for parents that can have lots of children. For parents that only have a few small children, where the children are almost always visited when you visit the parent, I'm getting Hibernate to load the children for me when the parent is loaded.

      The tradeoff is between code complexity (having to inject the service into the parent adds complexity) and performance (getting Hibernate to load the children when you load the parent will often result in unnecessary database hits). I'm evaluating this tradeoff for every parent-child relationship. Perhaps this is a bad idea because I'll be mixing two different mechanisms but as yatesco says "sometimes just getting on with an imperfect solution is better than no solution".

      Comment


      • #48
        Originally posted by wexwarez
        i really don't think i should have to go making little interfaces for everytime my domain object needs access to a getter like this from the service layer. There must be another alternative.
        I had a mental argument with myself last week regarding the "little interfaces" issue. First of all, let me describe this problem to see if we agree what it is. Let's say you have classes ParentA, ParentB, etc. and each one of them depends on a service that loads their children -- for example, getParentAChildren(), getParentBChildren(), etc. The issue is, do you put all of these services in one big interface (e.g. ChildLocator) or do you put each service in a separate, small interface (e.g ParentAChildLocator, ParentBChildLocator, etc)?

        My initial thought was "put each service into a separate interface" to reduce coupling (e.g. ParentA is not coupled to getParentBChildren() and ParentB is not coupled to getParentAChildren()). However, after considering the number of parent-child relationships in my model, I figured I might need many (tens of or even hundreds of) of these small interfaces. This just seemed like too much of a hassle, especially if I switch to using DependencyInjectionInterceptorFactoryBean later on. So, I decided (for now) to use a compromise solution -- a few large interfaces that hold related (by subsystem) child locator services. For example:

        Code:
        interface InventoryService  
        {
          Collection getInventoryParentAChildren(long inventoryParentAId);
          Collection getInventoryParentBChildren(long inventoryParentBId);
        
          //...other services
        }
        
        interface CustomerService  
        {
          Collection getCustomerParentAChildren(long customerParentAId);
          Collection getCustomerParentBChildren(long customerParentBId);
        
          //...other services
        }

        Comment


        • #49
          Umm, surely you would have have a single "Locator" interface and pass the appropriate implementation in at run time? Maybe I am missing something

          Comment


          • #50
            Originally posted by yatesco
            Umm, surely you would have have a single "Locator" interface and pass the appropriate implementation in at run time? Maybe I am missing something
            Yes and no. I do pass the appropriate implementation in at run time, as you suggested several posts ago with int getSum(ChildEntityLocatorStrategy, FilteringParams). However, I have a few coarse-grained interfaces (with services grouped by subsystem) instead of one separate interface for each and every locator service. I realize this has to potential to increase coupling but this is mitigated by the decrease in the number of interfaces. It's a tradeoff. I don't want the hassle of source controlling so many separate fine grained interfaces, especially if I might switch to using DependencyInjectionInterceptorFactoryBean at a later date.

            Comment


            • #51
              Originally posted by cyboc
              I had a mental argument with myself last week regarding the "little interfaces" issue. First of all, let me describe this problem to see if we agree what it is. Let's say you have classes ParentA, ParentB, etc. and each one of them depends on a service that loads their children -- for example, getParentAChildren(), getParentBChildren(), etc. The issue is, do you put all of these services in one big interface (e.g. ChildLocator) or do you put each service in a separate, small interface (e.g ParentAChildLocator, ParentBChildLocator, etc)?

              My initial thought was "put each service into a separate interface" to reduce coupling (e.g. ParentA is not coupled to getParentBChildren() and ParentB is not coupled to getParentAChildren()). However, after considering the number of parent-child relationships in my model, I figured I might need many (tens of or even hundreds of) of these small interfaces. This just seemed like too much of a hassle, especially if I switch to using DependencyInjectionInterceptorFactoryBean later on. So, I decided (for now) to use a compromise solution -- a few large interfaces that hold related (by subsystem) child locator services. For example:

              Code:
              interface InventoryService  
              {
                Collection getInventoryParentAChildren(long inventoryParentAId);
                Collection getInventoryParentBChildren(long inventoryParentBId);
              
                //...other services
              }
              
              interface CustomerService  
              {
                Collection getCustomerParentAChildren(long customerParentAId);
                Collection getCustomerParentBChildren(long customerParentBId);
              
                //...other services
              }

              Yes we are on the same page. These locators are such common occurances that it is very tedious to create these mini-interfaces constantly and generally the service interface may encompass actions for many domain objects making it somewhat inappropriate. Neither method is ideal, especially for a lazy programmer.

              But my whole beef with this is that I don't think it is appropriate to be passing service interfaces into the domain object. In my mind there are 2 possible places you could inject the service interface:
              1)Upon request
              Code:
              //some code in the view
              Iterator it = a.getBChildren(myService).iterator();
              while (it.hasNext() {
              displayB((B) it.next());
              }
              When you set it up so you always manually inject myservice in at runtime then you often get into situations where the view layer has to mess around with the service in order to present the model. This is very messy.

              2)Injecting the service as a dependency into the stateful domain object.
              This opens up a lot of options but I don't think any of them are good.
              Code:
              public class A
              {
                private AServiceInterface aServiceLayer;
                private int id;
              //inject the service layer through the setter   
                public void setAServiceLayer(AServiceInterface aServiceLayer)    {
                    this.aServiceLayer = aServiceLayer;
                  }
                public int getId() {
                  return id;
                }
                
                private Collection bChildren;
                
              public Collection getBChildren() {
                //we can perform the lazy load using the injected service layer    
                if (bChildren == null) 
                    bChildren = aServiceLayer.getBChildren(id)
                      return bChildren;
                }
                public void setBChildren(Collection b) {
                  this.bChildren =b;
                }
              }
              First of all you won't be creating these domain objects with spring and doing the injection through config because they are stateful beans. Now if you are getting the A bean through a finder in the service layer you could inject it there:
              Code:
              public class DefaultAServiceLayer {
              
                public A getA(int id) {
                  A returnValue = findA(id);
                  returnValue.setAServiceLayer(this);//inject the service layer during the load
                  return returnValue;
                }
              
                public Collection getBChildren(int id) {
                //code omitted
                }
              }
              This isn't so bad. But what happens if you create a new instance of A.
              Code:
              //some code somewhere
              A a = new A();
              a.setAServiceLayer(defaultAServiceLayer);
              In this case whenever you create a new instance of A you need access to the defaultAServiceLayer. I guess this isn't horrible but it isn't great either. I don't like that you need to have access to this serviceLayer just to create a new instance of A. Dependency Injection is great when it is automated in configuration and you aren't required to remember to do it all over the code. When you are required to remember dependencies like this i tend to write bug prone code. The only other solution is to do it through constructor injection. But who wants messy constructors?

              I guess that because this requirement is so common i expect there to be a better, Cleaner solution.

              Comment


              • #52
                Originally posted by wexwarez
                ...you often get into situations where the view layer has to mess around with the service in order to present the model. This is very messy.
                Well, usually the view layer will have some sort of dependency on the business service layer anyway. If it didn't, how would it get its data to display and how would it access business logic? Those jobs should probably be delegated to the service layer (they shouldn't be done in the view, except in perhaps a very trivial application). So, the view probably already has a dependency injection setter that looks like this:

                Code:
                interface MyView
                {
                  void setSomeService(SomeService someService);
                
                   // other methods. e.g. displayThis(), displayThat(), whatever
                }
                Now you can either add another DI setter for a separate child locator service or you can put the locator methods in the SomeService interface. For now, I have been adding the locator methods to the SomeService interface. This is because: 1) my locator methods were related to the same subsystem as the SomeService interface, and 2) I had already setup a SomeService dependency in my bean config file that MyView is defined in.

                As a more concrete example, consider an Order subystem in an order processing application. You could have this view interface:

                Code:
                interface OrderView
                {
                  void setOrderService(OrderService orderService);
                
                   // other methods. e.g. displayOrder(), displayOrderItems(), whatever
                }
                And you could have this service interface:
                Code:
                interface OrderService
                {
                  void placeOrder(Order order);
                  Order loadOrder(long orderId);
                  Collection loadOrders();
                
                  // "child locator/loader/whatever you want to call it" method that 
                  // loads the the child items for a given Order
                  Collection loadOrderItems(long orderId);
                }
                Note that I put the loadOrderItems method in the OrderService interface instead of a separate OrderItemLoader interface. I chose to do this because the loadOrderItems() method is related to the Order subsystem in my application and also because OrderView already has a dependency on OrderService anyway. Why set up another DI setter? In the future, if I switch to using DependencyInjectionInterceptorFactoryBean I have less code and less configuration settings to prune.

                Originally posted by wexwarez
                I guess that because this requirement is so common i expect there to be a better, Cleaner solution.
                There is: DependencyInjectionInterceptorFactoryBean. The first snippet in the JavaDocs for this class says "Allows Spring to create and wire up objects that come from Hibernate. This enables richer domain models, with domain objects able to access business objects."

                My only hesitation with DependencyInjectionInterceptorFactoryBean is that it is still in Spring's sandbox (i.e. it is not in the main source tree yet). wexwarez, how about you could give it a try and report back with to us?

                Comment


                • #53
                  Originally posted by cyboc
                  Well, usually the view layer will have some sort of dependency on the business service layer anyway.
                  In most of my code it sure does. But I thought "ideally" you create a model and send it to the view. And in my eyes this parent object would just be part of that model and the view would traverse it to display what it needs to, ie the children.

                  cyboc i am a little unclear, what you are suggesting is just to leave the domain object with a method like so:
                  Collection getBChildren(ChildrenLocatorServiceInterface i)

                  And then just rely on that service interface being available whenever you need to get B children?


                  This whole lazy load thing is certainly a lot of trouble, although performance wise it seems to be irreplacable.

                  Originally posted by cyboc
                  My only hesitation with DependencyInjectionInterceptorFactoryBean is that it is still in Spring's sandbox (i.e. it is not in the main source tree yet). wexwarez, how about you could give it a try and report back with to us?
                  i'll get right on that...

                  Comment


                  • #54
                    Originally posted by wexwarez
                    Originally posted by cyboc
                    Well, usually the view layer will have some sort of dependency on the business service layer anyway.
                    In most of my code it sure does. But I thought "ideally" you create a model and send it to the view. And in my eyes this parent object would just be part of that model and the view would traverse it to display what it needs to, ie the children.
                    My bad for not being clearer. Of course you could have a model in the view layer that collaborates with a view. In our rich client app, it is usually the case that each "view" is really a triad of a view, a model and a controller. Usually we set the service layer dependencies on the model (although, there are a few places where it was set on the controller). My point is that some component of each of these triads in the view layer usually needs a business service layer dependency to help it carry out its job.

                    Originally posted by wexwarez
                    cyboc i am a little unclear, what you are suggesting is just to leave the domain object with a method like so:
                    Collection getBChildren(ChildrenLocatorServiceInterface i)
                    Yes, that's my suggestion (thanks for yatesco for original idea). Note that I'm only using this mechanism for parent-child relationships with LOTS of children per parent where it is NOT likely that you will visit a large proportion of those children in every use case. For relationships with only a few children or relationships where it is likely that most of the children will be visited in every use case, I'm getting Hibernate to automatically load the children. In other words, I'm considering each parent-child relationship on a case by case basis.

                    For example, in an accounting system you could have this parent-child hierarchy: Journal->Transaction->LineItem, where a Journal can have a LOT of Transactions but each Transaction usually only has 2 LineItems (one debit, one credit). In this case, you might want to use the child locator mechanism to load a Journal's Transactions whereas you might want to use Hibernate to automatically load a Transaction's LineItems.

                    I realize that this leads to inconsistencies (i.e. two ways of doing the same thing) but on the balance of pros and cons (see previous posts) it seems to work best for my needs (at least until DependencyInjectionInterceptorFactoryBean is moved into the main source tree). Your mileage may vary.

                    Originally posted by wexwarez
                    And then just rely on that service interface being available whenever you need to get B children?
                    Yes. That service interface will probably already be available because you will probably need it to get the parent, e.g.:

                    Code:
                    interface MyService
                    {
                      Parent getParent(...);
                      Collection getChildren(parentId);
                    
                      //other methods...
                    }
                    
                    interface MyView (or MyViewModel, whatever)
                    {
                      void setMyService(MyService)
                    
                      //other methods...
                    }

                    Comment


                    • #55
                      Joe,

                      I actually wrote the first version of DependencyInjectionInterceptorFactoryBean and have been using my original version and then Rod's newer version it in production for over 1.5 years with out a single problem.

                      Though I should point out that I am only using the prototype bean mode, I'm not a big fan of autowiring in general and I believe it's not nearly as performant as the prototype mode.

                      Ollie

                      Comment


                      • #56
                        Originally posted by oliverhutchison
                        Joe,

                        I actually wrote the first version of DependencyInjectionInterceptorFactoryBean and have been using my original version and then Rod's newer version it in production for over 1.5 years with out a single problem.

                        Though I should point out that I am only using the prototype bean mode, I'm not a big fan of autowiring in general and I believe it's not nearly as performant as the prototype mode.

                        Ollie
                        Cool! If it has your stamp of approval, I guess I could try it in one parent-child relationship. Could you please elaborate on the prototype mode versus autowiring mode in relation to DependencyInjectionInterceptorFactoryBean?

                        Comment


                        • #57
                          Basically you have two choices about how DependencyInjectionInterceptorFactoryBean will go about creating your domain objects.

                          1) By mapping the domain objects class to a prototype bean in the your app context. So basically you configure DependencyInjectionInterceptorFactoryBean to return a new instance of the bean "aPrototype" from the app context whenever Hibernate wants a new instance of A.class.

                          2) By applying the general autowiring capabilities of the app context to a new instance of the required class. So in this case DependencyInjectionInterceptorFactoryBean creates a new instance of A.class and then autowires it using the app context.

                          Obviously 2 is going to be much slower as each time Hibernate needs a new instance of your domain object the app context is going to interrogate all of it's properties to find any autowiring opportunities.

                          Here's a snipit of config to get you started:
                          Code:
                              <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">    
                                  <property name="entityInterceptor"><ref bean="springDependencyInjectionInterceptor"/></property>
                                  <property name="dataSource"><ref bean="fullAccessDataSource"/></property>
                                  <property name="configLocation"><value>/ourcommunity/cfg/hibernate/hibernate.cfg.xml</value></property>
                                  <property name="hibernateProperties">
                                      <props>
                                          <prop key="hibernate.dialect">net.sf.hibernate.dialect.SQLServerDialect</prop>
                                          <prop key="hibernate.use_outer_join">true</prop>
                                          <prop key="hibernate.show_sql">false</prop>
                                      </props>
                                  </property>
                              </bean>
                              
                              
                              <bean id="springDependencyInjectionInterceptor" 
                                class="org.springframework.orm.hibernate.support.DependencyInjectionInterceptorFactoryBean">
                                <property name="sessionFactoryName">
                                  <idref local="sessionFactory" />
                                </property>
                                <property name="managedClassNamesToPrototypeNames">
                                  <props>
                                    <prop key="ourcommunity.giving.Appeal">appealPrototype</prop>
                                    <prop key="ourcommunity.membership.Membership">orgMembershipPrototype</prop>
                                  </props>
                                </property>
                              </bean>
                          
                              <bean id="appealPrototype" class="ourcommunity.giving.Appeal" 
                                singleton="false" >
                                <property name="appealServices">
                                  <ref bean="appealServices" />
                                </property>
                              </bean>
                          	
                              <bean id="orgMembershipPrototype" 
                                class="ourcommunity.membership.Membership" singleton="false" >
                                <property name="membershipServices">
                                  <ref bean="membershipServices" />
                                </property>
                              </bean>
                          Ollie

                          Comment


                          • #58
                            Ollie,

                            Thanks very much for those snippets! They will save me much searching!

                            Does DependencyInjectionInterceptorFactoryBean work with both Hibernate 2 and Hibernate 3?

                            Any caveats with using DependencyInjectionInterceptorFactoryBean? For example, does it make testing harder?

                            Comment


                            • #59
                              Does DependencyInjectionInterceptorFactoryBean work with both Hibernate 2 and Hibernate 3?
                              I only use Hibernate 2 and I suspect it does not work with 3 as, from memory, the Interceptor class has changed plus the package structure's change as well.

                              Coding a H3 compliant version should be easy as Rod refactored all the generic code into a superclass DependencyInjectionAspectSupport. I guess you'd just copy the existing classes ChainedInterceptorSupport and DependencyInjectionInterceptorFactoryBean update to the H3 package structure and fix any errors.

                              Ollie

                              Comment


                              • #60
                                I'm gonna stir things up a bit and possibly get flamed. So, how about an aspect? This is how Hibernate implements lazy loading - it applies what amounts to an aspect to your class (or collection) so that it will be lazily loaded upon the first access. Of course, Hibernate's lazy loading doesn't work outside of a session, thus the need for a "service". What if you had an aspect you could wrap around your class and tell it "when getChildren is called for the first time, invoke method loadChildren on this service interface and then call setChildren on the domain object passing in the return value of the loadChildren method"? This will keep the service dependency out of your POJO domain object and move it into the aspect. Of course, you still have the problem of applying the aspect to an object whose lifecycle is controlled outside of Spring. But this might not be such a hard problem to solve. For example, in our architecture, all domain objects are "loaded" via service methods. These service methods are wrapped in a transaction, and our Hibernate session lasts the duration of the transaction. This means that if code within the service method happens to need access to the children, then it can just call "getChildren" and utilize Hibernate's built in lazy loading. So, the only time you need this aspect I've described is when you are using the domain object outside of the service method. The only way the object gets outside the service method is via the service method's return value. So, create a second aspect that wraps the service and intercepts the return values of specified service methods and wraps eligable objects contained within the service method's return value with our lazy-loading aspect. Whew. Sounds hard, but once all the machinery is in place, it's probably pretty easy to reuse in other services. I imagine all this being configured via Spring, of course - and probably in much the same way as declarative transactions are done now.
                                This would keep your domain objects "pure" and allow you to swap out lazy loading strategies in the future (simply by applying a different aspect to the domain object).

                                Comment

                                Working...
                                X