14 Replies Latest reply on May 22, 2008 12:03 PM by alexg79

    Entity bean cascade design issue

    alexg79

      I'm sure that a lot of others have run into the same problem as I have.
      Suppose you have three entity bean classes: Employee, Customer, Order.
      an Order is associated to one Employee and one Customer.
      What if an employee who has associated orders gets fired? You can't simply delete his Employee record, because the association from Order prevents it. Orders may not be deleted because you have to keep them all for statistics.
      I can think of three ways to handle this:
      1. Have the code that removes the Employee nullify the connection to the Employee
      2. Use weak references instead (store the ID of the Employee without a foreign key constraint)
      3. Use a unidirectional one-to-many association

      Problems:
      1. Not very scalable, since you have to remember to only remove the entities in question through one specific method, and the method has to know of every single association
      2. Can leave dangling IDs behind when the target is removed, and references require explicit queries
      3. Ugly, not spec compliant and requires an additional table per association, and association is not visible from the Order object

      Is there nothing like "ON DELETE SET NULL" for EJB 3.0 persistence, or Hibernate?
      Do I have to resort to native SQL for this?

        • 1. Re: Entity bean cascade design issue
          weston.price

          How about assigning the Order to another Employee. From a business perspective this would probably make the most sense right as Orders wouldn't just 'dissapear' everytime someone got canned or we would all be in trouble ;-)

          • 2. Re: Entity bean cascade design issue
            alexg79

            This is just the same as my solution #1, and has the same problems.
            Besides, this was just an example -- I have lots of other associations like this in my project, with different semantics.
            Oh, and by the way, solution #1 didn't involve removing the Order -- that'd be bad -- only severing the link to the Employee.

            • 3. Re: Entity bean cascade design issue
              weston.price

              Right which is why I mentioned assigning an 'new' employee to own the Order. I didn't mean for you to blow it away. It was a joke.

              You would usually assume the Order would have to be tied to some existing employee and that employee would have to exist. Semantically I don't think it makes a lot of sense to have an Order without a customer which pretty much dictates #1, at least for this particular situation.




              • 4. Re: Entity bean cascade design issue
                alexg79

                 

                You would usually assume the Order would have to be tied to some existing employee and that employee would have to exist. Semantically I don't think it makes a lot of sense to have an Order without a customer which pretty much dictates #1, at least for this particular situation.

                Uh...if the order has already been processed, and you reassign it to someone else, that person's sales record would be skewed.

                • 5. Re: Entity bean cascade design issue
                  weston.price

                  And removing the Employee for the Order, what happens to it then? How does it get recorded as a transaction? I would assume some form of reconciliation has to take place on the Order at some point. If the Employee/Order relationship is part of that reconciliation things are going to get skewed without that association as well.

                  If the Employee/Order relationship is not required for the business, then leaving the dangling ID might be acceptable.







                  • 6. Re: Entity bean cascade design issue
                    alexg79

                     

                    And removing the Employee for the Order, what happens to it then? How does it get recorded as a transaction? I would assume some form of reconciliation has to take place on the Order at some point. If the Employee/Order relationship is part of that reconciliation things are going to get skewed without that association as well.

                    I don't have the faintest idea what you're talking about. Why would it need to be "recorded as a transaction"?

                    If the Employee/Order relationship is not required for the business, then leaving the dangling ID might be acceptable.

                    And this is better than setting it to null how? Being able to refer to the Employee while the Order is still unprocessed is a major convenience (which is what bidirectional associations are all about).
                    Maybe I could use some kind of an interceptor that automates setting the property value to null?

                    • 7. Re: Entity bean cascade design issue
                      weston.price

                      Simple Google:
                      http://opensource.atlassian.com/projects/hibernate/browse/ANN-250?decorator=printable

                      You presented three 'choices' in your original post, I was just trying to get an idea of your requirements and what it would mean to leave a dangling ID, or set the Employee relationship to NULL. I wasn't advocating any particular approach out of the three.



                      • 8. Re: Entity bean cascade design issue
                        alexg79

                         

                        Simple Google:
                        http://opensource.atlassian.com/projects/hibernate/browse/ANN-250?decorator=printable

                        There we have established that Hibernate does NOT have the OnDeleteAction.SET_NULL feature. I hope it some day will, since according to the Google searches I made, a considerable number of developers would like to have this feature.
                        Back to the problem.
                        Would you consider an interceptor the best solution for this? Or just designing the application to manually sever the links prior to deleting the Employee?

                        • 9. Re: Entity bean cascade design issue
                          weston.price

                          Personally I would go the interceptor route just to get the on/off behavior if necessary. Another nice thing about the Interceptor approach is that once the feature is implemented you can just remove it rather than having to change code and rework parts of your application.





                          • 10. Re: Entity bean cascade design issue
                            alexg79

                            Hey, I just got an idea. Would this work?

                            @Entity
                            public class Order {
                            private Employee employee;
                            ...
                            }
                            
                            @Entity
                            public class Employee {
                            ...
                            private List<Order> orders;
                            ...
                             @PreRemove
                             public void removeRefs() {
                             for (Order o : orders)
                             o.setEmployee(null);
                             }
                            }
                            


                            If this works, it'll be an elegant enough solution.
                            At least it'd save me the trouble of creating my own interceptors for this.

                            • 11. Re: Entity bean cascade design issue
                              weston.price

                              Hmmm...I can't see why it wouldn't. That is quite elegant. One thing you could do, try it and also do the Interceptor. Test both...nice thing about annonations and interceptors together is that you can remove one or both.

                              • 12. Re: Entity bean cascade design issue
                                alexg79

                                Hey, I just got an idea. Would this work?

                                @Entity
                                public class Order {
                                private Employee employee;
                                ...
                                }
                                
                                @Entity
                                public class Employee {
                                ...
                                private List<Order> orders;
                                ...
                                 @PreRemove
                                 public void removeRefs() {
                                 for (Order o : orders)
                                 o.setEmployee(null);
                                 }
                                }
                                


                                If this works, it'll be an elegant enough solution.
                                At least it'd save me the trouble of creating my own interceptors for this.

                                • 13. Re: Entity bean cascade design issue

                                  Hi!!
                                  I was searching info about ON DELETE SET NULL equivalent in EJB. All I found is that (probably) this is not implemented. Is this true?

                                  The approach commented this post (with @PreRemove annotation) is correctly working. Can anybody post an example of an interceptor for this?

                                  What are the pros and cons of each one?


                                  Thanks in advance!

                                  • 14. Re: Entity bean cascade design issue
                                    alexg79

                                     

                                    I was searching info about ON DELETE SET NULL equivalent in EJB. All I found is that (probably) this is not implemented. Is this true?

                                    For some incomprehensible reason, Hibernate devs consider this functionality "bad design", even though RDMSs have supported it for a long time now. I've never heard an explanation for this, but in practice they've left us hanging. This approach was the best substitute I could think of.