Map Logical Entities to more than one EnterpriseBean

Discussions

J2EE patterns: Map Logical Entities to more than one EnterpriseBean

  1. It's a well-known design pattern for EJB applications to use coarse-grained instead of fine-grained Entity Beans. It's also a best practice to introduce the concept of ownership of database structures and implementation for components - after all, that's what they should encapsulate. Looking at the EJB1.1 spec, an Entity Bean can only be used if access to specific instance (identity) is required. For example, a Customer Entity Bean will allow access to all of a customer's attributes.

    But how to you implement methods that operate on more than one entity? For some scenarios, the spec provides a solution - namely, the creation, finding and removal of entities. But how about methods that, for instance, compute a statistical result (number of customers with more than 100 employees, sales regions and the customers located therein etc.)? You obviously don't want to implement those methods in a Session Bean that accesses the Entity Bean to compute the results (this would result in the worst possible performance). How can you use an Entity Bean to implement those methods?

    Basically, you can't - at least not in EJB1.1. EJB 2.0 introduces the concept of additional methods in the bean's home interface, so you can put methods for the purposes described above in the there, together with different findBy and create methods. In EJB1.1, however, you have to introduce a second bean to handle those methods. Technically, this is a second component; logically, it isn't.

    So the pattern described here is: Define your Logical Entity Components, preferrably using your CASE tool of choice. Define methods that access a single entity, and methods that operate on multiple entities, all in the same model element. To make things easier, use code generation to produce both the entity bean and a stateless session bean, each containing the appropriate methods. View the two EJB components logically as a single component - i.e., apply all the architectural rules you have to both of them *together*. For example, they can share implementation classes, use the same data access objects etc. You also want to put them into the same .jar file.

    When your container starts supporting EJB 2.0, change your code generation process to map the multiple-entity methods to the extended home interface.

    Stefan Tilkov
  2. <quote>
    But how to you implement methods that operate on more than one entity? For some scenarios, the spec provides a solution - namely, the creation, finding and removal of entities. But how about methods that, for instance, compute a statistical result (number of customers with more than 100 employees, sales regions and the customers located therein etc.)?
    </quote>

    Use SQL, it works.

    <quote>
    How can you use an Entity Bean to implement those methods?
    </quote>

    You don't want to do that. Not even in EJB 2.0.
    Although the relational model still lacks support for inheritance, it is still a lot better than "Entity Bean model", because the former doesn't exist (or at least I am not able to find it).

    Also the database server is able to optimize operations on sets.
    If you want to devise , or you wait for the EJB 2.0 to bring some kind of findBy(...).apply(Operation), you will know how the performance will look like.

    Cheers,
    Costin
  3. Hi Costin,

    you missed my point. Of course you compute the results for the examples I provided using SQL (what else?). Instantiating thousands of Entity Beans (or objects, nearly as bad) instead of issueing a single SQL statement is absolutely stupid. We agree on this, right?

    But where do you put that SQL statement? I think you have to put it in some Java method, belonging to a class. Now where does that class reside? Obviously the method is implemented with knowledge of the SQL schema that lies below the Entity Bean. As the component is called something like "Customer" or "Product", I want it to be a facade for everything connected with saving the customer, so (if using EJB 2.0) I'll put it into a home method (and use BMP or a CMP ejbSelect). If I don't have EJB 2.0, I use the pattern described above (that is, I'll put the method (and others like it) into a Stateless Session Bean that logically belongs to Entity Bean, forming a logical entity component.

    Regards,
    Stefan
  4. Right,

    I was confused by some formulations and the title of the pattern.

    If you only want to discuss where exactly the SQl statements hsould be, I don't find it particularly as important as a pattern, it is more a "best practice".

    However, more interesting is that if you use SQL statements, you have to be aware that in conjunction with Entity Beans there can be awkward interactions, due to incompatibilities of the two models.

    For instance if you modified some beans and in same transaction you use SELECT .. WHERE ... you might get wrong results, because ejbStore() methods are ususally deferred.
    Also, if you use UPDATE , DELETE directly with SQL the state of the database might be incompatible twith the existing Entity Beans.

    Therefore:
     a. Don't use Entity at all
     b. Document very clearly where it is possible to issue direct SQL statements.
       Don't operate with SQL and with Entities in the same transaction.
       If possible, implememnt a state machine to enforce this.

    Regards,
    Costin
  5. One can always argue about what qualifies as a pattern and what doesn't. The main idea in what I proposed is to put all the logic concerned with a particular entity into a cohesive unit, a pair of technical components forming a logical one. As this is a structural issue rather than something only concerning implementation, I think it does qualify.

    <q>
    However, more interesting is that if you use SQL statements, you have to be aware that in conjunction with Entity Beans there can be awkward interactions, due to incompatibilities of the two models.
    [...]
    </q>

    Again, I may not have expressed myself clearly enough (looking over my initial description, I probably shouldn't have mentioned CMP at all). The issues you describe are concered with mixing direct JDBC calls with CMP Entity Beans, something I have no experience with - in EJB 1.1, I have always used BMP (and I consider it to be the only viable option). If only EJB 2.0 was there now ...

    <q>
    Therefore:
     a. Don't use Entity at all
     b. Document very clearly where it is possible to issue direct SQL statements.
    </q>

    You mean this in the sense of "either/or", right? Anyway, the problems you describe only occur if you use the pattern to encapsulate *update* operations - select statements don't have those problems.
  6. Well,

    The problems are there also for select, because select have the where and having clause, and if you have made some updates against the EJBs that interfere with select criteria you can get wrong results.

    The Entity EJB way of doing things is select all the information at the begining, update all things at the end.
    It is a valid way of doing things, but not necessarily the best one , and certainly if you mix in independently issued SQL statements the model does not offer you any guarantees.

    If you really control things, you can solve this issues case by case.

    The problem is that these issues should have been solved automatically by a correct model.
  7. I see you point - there is a problem if one issues Entity Bean updates, followed by select clauses, in that order and in the same transaction. Somehow I have not yet run into that restriction, basically because in my model, each client/server interaction starts and ends a new transaction; but the point is still valid.

    Regards,
    Stefan
  8. I have seen the exact problem that you have described, selects (via finders and direct JDBC) following changes to Entity Bean state giving surprising results. I saw this on a large Weblogic Server project several times this year.

    Typically it happens in really long TXs where someone changes a bean does a whole load of other stuff and then tries to find that bean (or underlying data) assuming that the state changes been committed to the database.

    The only way around this (that I'm aware of) is to make sure that you keep a reference to the modifed bean and use it in later operations, not re-find it. I think this confusion comes about if developers have used a lot of PL/SQL or other DB procedural langauge where this sort of pattern works.

    Ian.
  9. Such kind of "diamond" problems are already documented by the EJB spec...don't have any special for this case.