|
First off, "Mo" stands for ManagedObject. So what we are saying with the call to getPathProxyFromMoArray() is, "Give me an array of ManagedObjects representing a path, and I'll give you back the PathProxy -- the one and only unique PathProxy -- which points to that node. This last point is important. There is at most one PathProxy for every unique path.
Notice that getPathProxyFromMoArray() also has a boolean switch to determine if a PathProxy should be generated if one is not found: createIfNotFound. For some operations it makes sense to create the PathProxy, for example, when you are adding a child to the path. If you are deleting or checking for the existence of children, however, it does not make sense!
The core idea behind finding a PathProxy is building an HQL query (actually, a JPA-QL query) that will return us the unique PathProxy for the Object array. We do this by saying, "select from pathProxy pp where pp.entityType = ? and pp.entityId = ? and pp.parent.entityType = ? and pp.parent.entityId = ? ...". Essentially, as long as there are more parents in the array, we slap on another .parent.
Footnotes to Listing 6I've added some footnotes to Listing 6, I'll quickly go over them here.
A: this line sets up the beginning of the Query. B: counts backward from the moArray because our path goes from parent-->child. This is just a decision. You could go from child-->parent.
C: begins a StringBuffer that will hold our "PathProxy clause".
D: adds on as many ".parents" as needed. You'll notice that the first time through, there is no ".parent" added -- that's because we want the first PathProxy to point directly to the first child. Basically, this inner for loop counts to 1 less than the number of path objects the outer loop has traversed , adding a .parent each time.
So (not to belabor the point but), the first time through there are no .parents added. The fifth time, there would be four: pp.parent.parent.parent.parent. The query adds a new part of the where clause that refers to each node in the path.
E: shows a little logical structure that takes our PathProxy clause and adds an .entityType and .entityId to two different Strings. Next, we add those together and add them to the query. If we're not at the end of the path yet, we append an "and" (see F). Also, because we have a ManagedObject to deal with, we can easily get the objects' ids (see inline comments).
Stepping back, I want to point out that we're using the Class names for the objects as their type. This has a lot of synergy with JPA, which also uses the Class to identify objects. We could have added a getType() method to ManagedObject and used that. I've found, though, that using the classname is a good solution.
G: shows an else that handles a null in the path array. This should occur only at the end of the array. At the end of the query, it will add a "... and pp.parent.parent.parent is null". As the inline comments note, if you are dealing with composite keys, Hibernate doesn't output the correct SQL, and you will get an error. You can usually get away with leaving this off, so long as your root-level objects are unique for the paths in your system.
Now we're at the point where we can execute the query and see whether we have a PathProxy or not. If not, we'll either create one or return null, based on the createIfNotFound flag. |
|