In reference to the MovieBean code with a CMR field in HFE on page 396, I wonder when the "DirectorId" column, which is a foreign key, will get populated in the "Movie" table. A reasonable guess seems to be that it gets popluated after the setDirector method is called (inside ejbPostCreate method in the sample code). But it brings up two questions: The first one is that if the above guess holds true, it may imply that it would take two separate steps for the container to create/populate a new record in the "Movie" table: 1) insert a new record to the table while leaving the "DirectorId" null -- this takes place after ejbCreate and before ejbPostCreate; 2) populate the "DirectorId" column by updating the newly added record after setDirector method is called. This insert/update sequence may NOT work if there is a "not nullable" constraint on the foreign key, which can very well be the case in a well-designed database. The bigger issue is that it also implies the container can NOT manage relationships for newly created entities. In other words, the code needs to be explicitly written (just like the code inside "ejbPostCreate" on page 396) to establish the relationship. I really wonder why the EJB spec doesn't allow the container to simply take the foreign key (presumably set inside "ejbCreate" along with other CMP fields) and find/set the CMR field automatically, which is exactly what the container does for the existing entities returned by the finder methods, i.e. figuring out the foreign key and setting the CMR field automatically. I cannot understand why the EJB designers didn't want the creator methods and finder methods to work in a more consistent manner in terms of how the container-managed relationship is handled. Any insights are greatly appreciated. [ March 03, 2004: Message edited by: Jiang Lin ] [ March 03, 2004: Message edited by: Jiang Lin ] [ March 03, 2004: Message edited by: Jiang Lin ]
While it *may* be the case that the container does an uncommitted database write between ejbCreate and ejbPostCreate, it is not a requirement of the spec. The only critical issue for a CMP bean is that between the completion of ejbCreate and before the start of ejbPostCreate the container must have establish the primary key for the entity. That is really why you need to wait until ejbPostCreate to establish any relationships. If you look at the OID diagrams in the spec, figure 26 versus figure 28 (pgs 207 and 210), you'll see that there is no requirement that a database write happen between ejbCreate and ejbPostCreate. You might, you might not (depends on how you cause primary keys to be generated, and how the CMR relationships are to be implemented).
Thanks, Reid. I totally agree with you -- the spec doesn't dictate when the database insert would occur, which is purely implementation dependent. However, I do feel that the spec poses certain (unnecessary?) challenge to both server providers and bean providers. From the server provider's perspective, the data needed to form a new record has to be collected in separate steps (collecting CMP fields in ejbCreate and then collecting CMR fields, i.e. foreign keys, in ejbPostCreate). From the bean provider's perspective, the code has to be written to manage (establish) the relationship for new entities even when the spec claims that the container will manage relationship automatically. Wouldn't it be nicer and cleaner if the spec can allow the bean provider to hand the foreign key values over to the container (in ejbCreate) and the container takes from there? Thanks again. [ March 04, 2004: Message edited by: Jiang Lin ]
Originally posted by Jiang Lin: Wouldn't it be nicer and cleaner if the spec can allow the bean provider to hand the foreign key values over to the container (in ejbCreate) and the container takes from there?
Understandable, but I think there are a number of very good reasons why the spec didn't take that approach (which is always open to the developer anyways - it just means the bean provider has taken over responsibility for managing relationships). 1. Relationships may not be managed by directly embedded foreign keys, they could be handled via intermediate relationship tables, stored procedures, database-specific object id management, etc. The concept of a bean provider giving a foreign key to an entity bean during creation may not map well to this. 2. The spec allows for unknown primary key classes. The bean provider may not even know how entities are keyed; single field, multiple field, generated via java code, generated via the database, etc. Again, the concept of giving the foreign key to ejbCreate may not seem so well formed. 3. EJB container vendors compete over performance. If you create a couple of related beans in the same transaction, there is a potential performance optimization to use for unknown primary key classes generated via the database... one query gets keys for all the to-be created entities, and then the newly created entities are written to the database. It cuts the number of database interactions approximately in half. This kind of optimization isn't possible without a very carefully crafted (even if not seemingly as clean) collection of lifecycle callbacks. 4. Bidirectional relationship navigation may require two entities to be updated - you don't just have to give the primary key for a director to a new movie, but the movie needs to be given the primary key for the director in order to maintain the relationship. The example HFE provides in the book suggests simpler options than the approach documented by the spec, but real projects deal with a broad range of relationships and optimizations and the spec tries to accomodate multiple approaches. Simplicity is nice, I definitely agree. It may just be that, given all the assorted real-world scenarios, the entity bean lifecycle and CMR handling is as simple as Sun could get.