You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Online: | 12 Members of 9401 |
| Forum: Weld Users |
31. May 2009, 21:02 America/New_York | Link |
In order to achieve Rich Domain Model it is often (very often in fact) necessary to inject objects managed by DI framework to entity beans. Current JSR-299 spec doesn't seem to support this in an easy way. You can of course access these objects programitcally but by doing this you lose DI benefits. Is there a way in JSR-299 to handle such a scenario? Maybe some Seam 3 extension is planned that uses Hibernate Interceptor, JSR-299 SPI or something else? What is WebBeans team view on solving this use case?
Regards, Rafał Hajdacki
It should be possible to use the JSR-299 SPI's BeanManager.createInjectionTarget() and the resulting InjectionTarget.inject(...) method to inject dependencies into an entity bean via a @PostConstruct callback of the entity bean. I don't know if a Seam3 extension is planned along those lines, but if not, I plan on rolling my own and sharing it, because I too dislike anemic models.
In my opinion, this is a horrible thing to do architecturally. Your domain model is the re-usable representation of your business. It should not be polluted by access to application-specific services.
Seriously, I'm a super-skeptic on architectural complexity, and I feel like I've spent my whole career advocating less layers, but even I don't advocate mixing your domain model, your infrastructural services, and your application-specific transaction logic into one big ball of dirty skanky nastiness.
Learn more about Weld...
Not to mention the fact that entities may be instantiated using new, even in a different physical tier of the application. An entity is not always a container-managed object. That's why it has the whole new-persistent-detached lifecycle model.
Do you really want to have to call Instance<Order>.get() to instantiate an Order?
Learn more about Weld...
Agree but what if one of my domain objects is not persistent but session scoped instead? For example session scoped Cart in online shop. I may be wrong but from high level perspective persistence can be considered as just another scope that is wider than @ApplicationScoped. We can come up with examples where nice OO design requires injection of session scoped domain object into persistent scoped domain object (similar to request scoped into session scoped injection). Gavin you wrote once that the power of Seam is that it doesn't enforce application structure on you. You just create classes the way it fits domain, Seam handles their lifecycle and you can use them directly from view (JSF) with very little or no plumbing code at all. I would extend that flexibility to persistent classes. What do you think?
BTW If you need some non-domain service layer then I agree that domain model shouldn't access it.
This would have to be solved by proper constructor I believe. In fact in nice OO design if object requires something it should be provided in constructor or method parameter. From this perspective no-argument constructor requirement in JPA spec can be considered a drawback but there are reason for that.
Completely agree, if you need entities that should travel across physical tiers then you shouldn't access external objects from them. But the same is true for lazy initialized fields that were not initialized. Accessing them requires external persistence service which is similar to accessing external service object.
Not really, I would like to use constructor injection in entities when they are created by EnitityManager and normal constructor instantiation in case of manual creation.
Regards, Rafał
Even if the Cart is persistent, you can easily put the Cart in the session scope using a producer method. You just would not be able to directly inject things into it (though you can inject into the producer method and pass the injected objects to the Cart constructor).
Or, if the point it is not persistent, what is the problem? You are trying to inject other things into it? Go ahead. Even if those other things
No, things in the database are not uniquely identifiable by type/bindings. You need to look them up explicitly using a query API.
I'm certain that whatever usecase you come up with can be easily and more elegantly expressed using producer methods.
I'm also unclear on whether you are talking about an injection that happens once when you first instantiate the entity, and is thereafter stored persistently in the database as an association, or an injection that happens every time the entity is loaded. Two very different possible semantics.
I don't think the analogy holds. There is an additional level of flexibility that is necessary in the case of entities: the flexibility to pass them around the system and use them in the absence of any container management. Secondly, in the case of entities, only very rarely do you encounter an entity that is singleton-ish. Normally, entities must be retrieved using queries, they can't just be without writing some code that specifies which one you're interested in. That code goes in the producer method.
Right. And if I directly instantiate an object using its constructor, how does the container get an opportunity to inject dependencies of the object?
Well, that would certainly be possible, and as Clint mentions, a portable extension could even provide that. But to me it seems like a very semantically weak kind of injection.
Learn more about Weld...
All of my comments below are only my $.02, with the implicit acknowledgement that you can create good and bad code regardless of your architectural approach, and hence my suggestions (and yours) can be misused by others, but that this misuse does not constitute a refutation of the worth of the approach in question. I also have a great deal of respect for your knowledge of architecture, in particular with regard to entities and dependency injection, Gavin.
If entities are containers of data, and only that, an argument against IoC in entities makes sense. However, when entities are true model objects, i.e. data and behavior representing a domain model, then they need to interact with other layers in order to accomplish the business logic they contain without resorting to skankiness. Interacting with other layers doesn't make you skanky. You do however need a clean way to do that. Injection is one such way.
The standard way to avoid adding IoC to model/entity classes is to leave them behaviorless (except for trivial validations that need no dependencies) and to shove all the logic into a DAO layer. That ends up creating horrible parallel graphs of and where the latter knows exactly how to hook a Foo to everything a Foo needs or that needs a Foo. Blech. A Foo at that point is essentially a C struct.
The repeated argument I've heard against adding dependencies to entities is simply that it's hard because sometimes the ORM creates entities and sometimes the application logic does, but that seems like an argument for creating a mechanism for handling that, rather than punting on making entities real objects.
I could go on, but it's better summarized here .
-Clint
I really think you're setting up a false dichotomy here. I've heard this same argument before from other people. It is claimed that:
But this argument is missing a couple of steps. First, you need to show that:
But I'm simply incredibly skeptical on both of these points. IMO, the kind of business logic that really belongs on your entities is the stuff that uses the entity, and other entities that are related to it by graph traversal, and not that you get by injection. And if you really can find me some cases where you need to use the random other stuff in an operation that truly does belong on an entity, I don't see why you can't just pass that stuff as method parameters from something else that you can inject into.
Learn more about Weld...
And by the way, I'm not at all in favor of an , and so the only thing about that Fowler article that I don't agree with is the idea that EJB somehow encourages it. Indeed, the original EJB entity beans were conceived as rather heavyweight components with method-level transaction and security demarcation that were responsible for implementing rather non-trivial transaction processing! So it seems like Fowler has things exactly backward on that point: it is the (meaningless term) model that does more to encourage the need for a service layer, since the service layer is absolutely needed for transaction and security management.
I think what happened here is the following chain of reasoning:
Whatever, note that the Fowler article has nothing to say on the subject of injection, and so we don't know (or even especially care) what he would think about the topic we're discussing.
Learn more about Weld...
Actually, on the contrary, those folks who do want to inject into entities should perhaps take another look at entity beans in EJB2. That architecture does seem to be more like what you're looking for. Combine the EJB2 Entity Bean component model with a decent persistence mapping layer, and EJB 3.1-style annotations, and dependency injection via 299, and away you go... :-)
Learn more about Weld...
I guess you'll need to tell me what is, because I see no canonical definition of this type of logic. To me, for example, the following things are useful things
I can think of a wealth of use cases for models to need each of those. Some examples:
Why on earth would that be required to make client code worthy of injection? In every case where you use injection there are other natural ways to get the injectable beans into the client code. We used these mechanisms for decades before injection arrived. Injection is simply cleaner, so we use it.
I'm trying to understand what motivates this preferenced distinction between and Why is behavior I can find in my referenced entities , but behavior I can find via injection (or without injection, via static methods) From my entity's perspective, the are injected. They're just injected by the ORM. And what you're really saying here is that only the ORM can inject things into an entity, because it knows what references an entity needs. But I told the ORM what things the entity needs, and I only told it things I needed to store in the database, because that's the role of the ORM. But there are other logical forms of dependencies that don't relate to object persistence, which are still dependencies my entity needs to do its job.
I can say the same of any object that uses injection. That's a straw man.
As an aside, did you never write:
in an entity (post-Seam), and absolutely love it? Why are we stopping there?
The point is that I have a good reason for thinking that entities should not depend upon things that they can only obtain from the container: the reason is that we often want to be able to serialize them around the system and use them in execution contexts where there is no container (or a logically different container).
Learn more about Weld...
Active record is the pattern that applies to the anemic domain model situation (there is actually some coverage of this in the SiA book when DAllen is covering the Seam Application Framework). I don't have experience with RoR or Active Record, but...
source: http://ar.rubyonrails.org
I'm not sure if I'd refer to ORM as inconvenient, at least we have HibernateTools (hbm2java specifically) and 1st and 2nd level caches; if you have that mind-set then use OODBMS like db4o, InterSystems Cache, etc.
I really think that application tx (aka atomic conversation) using SMPC and Hibernate MANUAL flushMode extension is a very useful tool in Seam apps.
Transaction support in ActiveRecord::Transactions::ClassMethods module is weak at best (e.g. no distributed tx support).
But if you really dislike anemic models, then use RoR or similar. Or find a way to integrate that into your JEE apps. Hey, at least the DTO pattern is now an anti-pattern in EJB3...
My concern is not so much the anemic domain problem as much as when will OODBMS and JEE integration become a JSR so we don't need to use ORM anymore. RDBMS has been around since the 70's, no? I know a lot of corporations are using RDBMS but finally they will be phased out with new technology like OODBMS. Ted Neward has blogged about the OODBMS topic a lot.
required reading: Scala and more Scala... www.artima.com
Is that the common case? I've never needed to do that. Maybe that's just me.
And even if it is the common case, entity injection availability doesn't require entities to necessarily use it; the author of an entity will know whether the it will need to be serialized to a different (container-less) execution context, and can code accordingly.
so it sounds like you guys are saying if it's available and you don't use it, then GKing's concerns are irrelevant in those cases (e.g. unit testing). JavaBean Seam components can have injections and implement java.io.Serializable, no? So if they can, why can't entity classes as well?
PEAA by Fowler does not cover DI at all.
I looked at the Active Record pattern in that book and the examples showed static CRUD methods in the entity class. Also business logic methods are in the entity class.
If your business logic is complex (relations, inheritance, etc), it's better to use Data Mapper.
I prefer not to have business logic in my entity classes.
But I guess the argument is, if for some reason we need to add business logic to entity class, then we may need injections?
But why do you need to have the biz logic in the entity class in the first place? What's wrong with separation of concerns and doing the biz logic in a JavaBean or EJB?
Or what about allowing DI in entity classes only via XML, not annotations?
How much do you really gain by adding biz logic methods to entity class? Perhaps you won't have to repeat code in multiple business components (DRY principle) if it's already a method in the entity class...
Overall, I'm siding with GKing on this one until somebody provides a concrete example of why/when you'd need DI in entity classes and what the gain/advantage is...
required reading: Scala and more Scala... www.artima.com
But in most cases they do depend on things that can be obtained only from the container: lazy initialized fields. We can think of external services similar to them. It is application specific, if you need transportable entities then don't use dependencies that may cause problems.
I want to handle use cases where request/seesion/application scoped object is accessed by entity. Great example provided by Clint is Logger.
Is that really a requirement for DI / scoping? It is just current state of things in JSR-299. We can come up with injection point that for example takes entity ID as parameter and injects Entity instance. Or even query in order to access collection of entities. This could work similar to Any in JSR-299.
I am talking about second case here. Don't want to store it in database.
This flexibility is not always required. This is application specific I think. If you want transportable objects you just don't expose not initialized persistent fields and external objects/services.
Does something have to singleton-ish in order to support injection? Well I just see EntityManger as just another context that I can access programmatically. As mentioned above we can also use query or entity id for injection point to support enity injection into other objects.
It doesn't. If you create objects manually you have to do it on you own.
Why is it semantically weak?
How about Logger injection into entities?
That's a perfectly legitimate requirement, and a good reason to be very careful about creating dependencies in the model layer if you have it. I've never had that requirement, nor do I see it as a natural endpoint for the types of problems we solve.
I think our difference on this issue may be due to our definition of To me, the only connotation inferred from the @Entity annotation is persistence. By designating an class an entity I am agreeing to obey the rules of JPA in order to make use of a JPA provider to map my object to a table. If (for example) one uses an entity in RMI situations, then that imposes additional requirements, but that's orthogonal to the question of what's good or bad for entities. That's why I accept the argument that the entity lifecycle complicates injection, because that argument is based on a characteristic that entities share by definition.
Gavin, but WebBeans's Logger is also not singleton-ish and yet you consider it a good candidate for injection. There are many instances of it from which only one is selected and injected using injection point metadata as id source. Entities can be handled in a similar way. The one thing that is different as Clint mentioned is more complicated life cycle of entities. But really is there anything in it that is a deal breaker for supporting injection?
I want to clarify that I am not advocating adding injection of entities to JCDI. That level of modification of the existing specification at this point in its lifecycle wouldn't be advisable or even feasible, and the semantics of entity injection needs a lot more thought in any case.
I am however advocating the investigation of a webbeans extension, either in Seam3 or otherwise, that would support this.
I am also not advocating it. In fact I am strongly against for doing it now. I am only arguing that considering persistence as just another context that can be handled by DI is feasible in general. But of course there are probably lots of issues hidden in JPA-JCDI integration in order to achieve it in an elegant way.
My point of mentioning this idea is to support general perspective that it is sensible to think about DI-managed and EM-managed objects as just domain objects that can access each other and that reasons for not doing so comes from other requirements/use cases that are not related to standard domain logic design.
Agree. This was my initial point starting this thread.
Seriously, if logging is the best usecase you can come up with...
Learn more about Weld...
seems like a kinda lame example to me :-)
This is a case of injecting entities into other things, not a case of injecting other things into entities. This can be handled today with magical things like producer methods and InjectionPoint.
Because its a field that is sometimes injected and so sometimes has the semantics specified by the annotations declared at the injection point.
Learn more about Weld...
I don't think logging by itself (one use case) qualifies as a solid case for allowing DI in entity classes. Although it may be more convenient to have access to DI in an entity class, you can still use JNDI lookup, no?
It really comes down to whether or not business logic belongs in an entity class. If it does (in some cases), then perhaps DI should be under consideration.
I mean do you really need to do some calculation, for example, in an entity class? Why can't that logic happen in a DAO, for example?
The only advantage I see with having the biz logic embedded in an entity class (as a public method), is you don't have to factor that method into an auxiliary helper class that is injected into a SFSB or DAO class everytime it is needed. So essentially it would cut down on coding. Especially in the case where you have an interface (e.g., Vehicle) which is implemented by Car, Truck, and SUV entity classes. That biz logic (calculation, etc.) may be common to all the entities and may in the interface or perhaps an abstract class with implementation.
So let's say you have a valid case and need to embed the public calculation method in the entity class, do we need access to EntityManager interface directly at this point for CRUD ops? I hope not. I think it's better to maintain separation of concerns, but at the same time minimize layering if possible.
This is one thing I agree on with GKing and one main reason I liked Seam from the beginning (no forced layering and patterns like Struts/EJB2.x!)
required reading: Scala and more Scala... www.artima.com
Seriously, if you don't consider logging a valid use case ... ;-) Why you have added injected logger to Seam and WebBeans extensions then? And who said it is the best use case? How about application scoped FileManager that abstracts access to files which we don't want to store in blobs? How about use cases provided by Clint?
That's for sure the ultimate argument Gavin. :-) Agree that logging seems trivial but it is still very frequent and valid use case. Let's make it less trivial then. How about audit logging that is common in financial/payment applications. You better make sure every financial operation is reported. And database is not always target storage for such audit traces. So injected AuditLogger would be very handy in entity beans. If this is lame use case then tell it to our customers. I would love to see their faces. ;-)
Please keep context of the discussion. I have provided ideas regarding injecting of entities into other things as example that the analogy of persistence to other context holds. And that injecting other things into entities is similar to injecting request scoped objects into session scoped objects. As arguments against that you first mentioned that which I showed is not requirement for DI. Second you argued that entities are not singleton-ish which I refuted by mentioning Logger which is also not really singleton-ish and yet fits DI (heck, you seem to have introduced InjectionPoint mostly to support such non singleton-ish cases). Third argument was that entities need to be transportable across container boundaries. But as me and Clint answered this requirement is really orthogonal to DI and also is not present in many applications.
Any other arguments against that analogy?
As for magical things provided by JSR-299, I am well aware of them as I follow spec changes and your blog since the beginning. As I mentioned in previous comment I don't argue here for adding support for alternative ways of entity injection into other things. This was just for the sake of argument.
Agree, such a injection is really semantically weak. You have to use Instance<Order>.get() to avoid that. But really when you create entity manually you are on your own to provide dependencies.
And Fowler most likely doesn't care about Seam or Web Beans as is evidenced by the fact that his blog entries are dated back to 2003, pre-EJB3, which is kinda lame. Nevertheless...
Why does he say you're ?
Validations is (mostly) solved by Hibernate validators. How often do we need calculations in CRUD apps in the domain model? And don't business rules belong in the business logic tier?
source: http://martinfowler.com/bliki/AnemicDomainModel.html
required reading: Scala and more Scala... www.artima.com
CBauer presented an auditing solution IIRC in Bauer/King book. Also........
source: http://www.jboss.org/envers/
So what is it about one of these two solutions that is insufficient for your logging/auditing use case?
Do you need one audit table for all entities or one audit table for each entity?
required reading: Scala and more Scala... www.artima.com
Agree. But sure it would be nice to have it. Don't you think? There are other cases. See my and Clint's previous entries.
Sure I can. But we have DI to handle this better. Right? Why don't you use JNDI lookup in services?
Even Gavin agrees that that it belongs in some cases. I would argue that it belongs in additional cases. OO is all about it, right?
Sure it can. But for OO-geeks it seems nice to have method that operates on data located in the same object as data. :-)
That's huge advantage. There are other benefits of OO design though. The are also drawbacks.
In most cases you just access local persistent fields like collections to do that. So no need to access EntityManager.
What are these concerns that should be separated?
Me too. But from my point of view Gavin is insisting on this last artificial layer. :-)
What do you mean exactly by ? Does that comment refer to DAO layer and/or entity class?
GKing is most likely not the only one in the EG's on this IMO.
Most likely there is some agreement from Linda DeMichiel and Mike Keith as well (I'm just guessing so shoot me if I'm wrong :).
It sounds like your intent here is to somehow this into the entity class and therefore take the JPA entity class back to what it was in EJB2.x as an which was more similar to Active Record pattern.
If you add injection and domain logic to your entity class, will it still be easily tested outside the EJB container? This was one of the main problems with EJB2.x and prior...
required reading: Scala and more Scala... www.artima.com
This approach is perfectly fine for simple auditing that just audits database operations. Unfortunately auditing in many cases is more complex then that. Imagine that auditing operations are use case specific and take different number of arguments for each use case. These arguments are not always related to changed entity and can't be provide in a declarative way. Add that it has to be plugabble to support different outputs. How would you handle such a use case?
This last layer are entities that shouldn't access other objects. For me they are just objects that have wider scope than application scoped beans and it is up to domain logic design to decided what should access what.
I am sure he is not the only one. From my experience I would even say that proponents of injection into entities are the minority. But I may be wrong. At least most applications I worked with doesn't use this kind of injection. :-)
I would really like to know all the arguments against this approach. I am not here to convince others to my view. I want to validate whether my view is valid. I haven't heard convincing argument yet though. Or maybe I am missing something.
No, I just want to treat entity as a real object that can access other objects using DI. :-)
Are your service objects testable outside EJB container? From my perspective entities can depend on objects located in other context. DI should provide these dependencies. Entity shouldn't know how they are provided. In test you can provide them manually or use DI framework for that. Similar to service objects.
Well unfortunatley, that's most likely not a typical use case. Which reminds me of my attempt a few months back (and GKing is well aware of this) to convince the JPA 2.0 EG regarding MANUAL flushMode as follows:
Mike Keith vehemently opposed. In fact, JPA 2.0 AFAIK does not support stored procs (Hibernate does).
My point is this: these outlying spec requests and/or use cases may not be seriously considered.
The JCP is with technical and political problems (the latter is unfortunate) and what is even more unfortunate is that you should be able to discuss this topic and other JSR/JCP related topics freely on discussion boards/forums sponsored by Sun but that's not currently available AFAIK.
required reading: Scala and more Scala... www.artima.com
AFAIK RoR is as anemic (or more) than @Entities, if you really do not like anemic models, use Apple EOF or Cayenne both of them help you create an architecture where the business logic is inside your entities, an approach completly different from the ActiveRecord one.
Is it? We still need them.
Many have tried that approach, and it has failed, specially performance wise, I do not think that the future are OODBMS, I think the future, if we are lucky, will be when we recognize that current RDBMS are not really relational, and what we dislike about them is not that they have limitations, what we dislike is that SQL is full of flaws, and we really need is a TRDBMs database with a truly relational language.
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
Then you like to create Anemic Domain Models
Well, in some architectures/frameworks, the is known as , so, it makes sense that the has the inside it.
There is nothing wrong.. if you like Anemic Domain Models
Think for example that you want all the purchases for a client, with an ORM, you tipically get them using client.getPurchases(); Now let say you want all the purchases in year 2000.... Does it make sense to be able to write: client.getPurchasesFromYear(2000); But you can not do that, because there is no way to inject the entityManager (or the purchases DAO) in to the client entity. So you end up with 2 very different ways of querying stuff, and in my experience you end up needing to query for the purchases of a client using may different filters (by year, between dates, by total cost, etc, etc). If you can ot write those queries as methods for the customer... then you will have to do that on a DAO (and if you use DAOs, then you are creating an Anemic Domain Model)
Take a look at this presentation Make Roles Explicit. Now think how convenient is to have IoC for the time when you need to change the implementation of a particular role to new, more efficient one, or to a new persistence service. That is why it would be really nice to have IoC on entities (it is not that it can not be done without it, we can do with plain JDBC anything that can be done with JPA, it is that it would be a lot more convenient)
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
There wouldn't any difficulty with wrapping the JPA EntityManager with your own that did injection. Actually sounds rather trivial to do with the SPI classes.
I think to win people over you should show some examples of this in practice.
Well, what is typical and what is not is very relative...and since Envers is pretty new I guess that Rafal approach is more common... specially since AFAIK Envers is Hibernate specific...
I do not see the relationship between MANUAL flushMode , and Injection into entity beans, but I do have a hard time understanding why MANUAL is needed... I also tried to convince the EclipseLink team to help me find a way to emulate FlushMode.MANUAL, to migrate to EclipseLink and avoid this hibernate bug, and take advantage of EclipseLink nested units of work (that are IMO a good match for nested conversations), but I end up convinced there was no real reason to have FlushMode.MANUAL (it would be nice to have a code example explaining what is so good about FlushMode.MANUAL, because I really do not get it) .
Yes, I agree 100% with you that we should have discussion boards/forums sponsored by Sun to discuss this kind of things, (maybe nabble will help with that? or maybe now that Sun is part of Oracle there will be a section for that in oracle forums?). I hope there be a way to ask Oracle for that.
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
Examples... like this presentation? ;)
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
@Stateful @ConversationScoped public class OrderConversation { @PersistenceContext(type=EXTENDED) EntityManager em; @Current Conversation conversation; private Order order; public Order getOrder() { return order; } public void load(int id) { conversation.begin(); em.setFlushMode(MANUAL); order = em.get(User.class, id); } public void addLineItemByAjax(Product product, int quantity) { order.addLineItem( new LineItem(product, quantity) ); } public void removeLineItemByAjax(LineItem li) { order.removeLineItem(li); } public void commitAllChanges() { em.flush(); conversation.end(); } }All changes are written to the database atomically at the end of the conversation. What's not to get?
Learn more about Weld...
And Seam could be adapted to achieve the same affect with em.setFlushMode(COMMIT); or not?
em.setFlushMode(MANUAL); delays flushing until em.flush();, em.setFlushMode(COMMIT) delays flushing until em.getTransaction().commit(); what is the big difference?.
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
GKing's above statement is true if you are using sequences (e.g. Oracle). If you are using IDENTITY to generate the next PK value, then it's possible that there will be commits/tx's to the db prior the em.flush() at the end of the LRC.
I never got a technical explanation (note the of the JCP in this respect) from Mike Keith regarding why he was opposed to MANUAL flush, most likely a political issue, who knows.
SiA:
In any event, this technique (atomic conversations) using SMPC (in Seam) and Hibernate MANUAL flush takes advantage of the 1st level cache of JPA/Hibernate. This means that your app will be less that other apps that use stored procs, for example.
If you think about this scenario, you don't even have to write a single JPAQL/HQL API statement to persist the data:
3 pages in a LRC (wizard). all pages, the user updates the form data and submits. the final submit button on the 3rd page flushes the EntityManager and ends the LRC. You don't need to write a single line of JPA code b/c at when the tx commits, the PersistenceContext is synchronized with the db tables (this is called write-behind).
SiA:
required reading: Scala and more Scala... www.artima.com
Because a JTA transaction corresponds to a database-level transaction. You are suggesting holding a database session and transaction open across user-think time? What happens if there is a limit to the number of available connections (this is how relational databases are priced). What happens if the user goes away - the connection/transaction gets cleaned up by a timeout?
This is something that has always been discouraged in applications that need to scale to many users. Now, it's not clear to me that this isn't just a problem with how today's JDBC drivers / relational databases are implemented, but I've not yet heard anyone saying that this advice is now out of date and that it is now perfectly fine to hold on to connections/transactions.
Now, could you, conceptually, introduce come kind of abstraction in the JTA layer? Yes, it is probably conceptually possible, but I think there would be a huge resistance to that, since it would require a major rethink to how statement-oriented APIs like JDBC work.
Learn more about Weld...
Arguably this is just a limitation in how Hibernate currently implements this feature. There's nothing conceptually broken about delaying id generation until the explicit flush occurs. Hibernate just doesn't know how to do this today.
Learn more about Weld...
I was about to write that this limitation was not existent on EclipseLink, but you beat me by writing that this is just a limitation in how Hibernate currently implements this feature, not an intrinsic ORM or even JPA limitation.
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
I think that the problem is that we do not carefully try to understand the perspective from the other people, we just do not place on their shoes, for example, back when I used EOF I never had this kind of problems, I had others, but transactions were plain easy, all I had to do:
And that was it. just a call to saveAllChanges and things were persisted in to the database, I did not had to worry about JDBC, JTA, transaction boundaries, the enditingContext handled it all (even offering nestedEditingContext) and this was more than 10 years ago. Basically no transaction was commited until saveAllChanges, all other queries were done in why Hibernate (or JPA) can not work that way? why I can not just query stuff in a (from the JPA user perspective) way and only worry about transactions when I commit? When I tried to explaing FlushMode.MANUAL to the EclipseLink guys they told me EclipseLink would do it (but I am not sure if they actually understood what I was asking for) they told me:
So... they seem to believe it is possible to avoid having a an open transaction during user think time using this ... Are they crazy? or.. what are they talking about?
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
Yes, from my point of view MANUAL flush mode is very handy and just makes sense in JPA. Gavin are you aware of any discussions in EG to add it to JPA 2?
What Doug is trying to say is that you can try to do it this way:
@Stateful @ConversationScoped @Transaction(NOT_SUPPORTED) public class OrderConversation { @PersistenceContext(type=EXTENDED) EntityManager em; @Current Conversation conversation; private Order order; public Order getOrder() { return order; } public void load(int id) { conversation.begin(); order = em.get(User.class, id); } public void addLineItemByAjax(Product product, int quantity) { order.addLineItem( new LineItem(product, quantity) ); } public void removeLineItemByAjax(LineItem li) { order.removeLineItem(li); } @Transaction(REQUIRED) public void commitAllChanges() { em.isOpen(); conversation.end(); } }Now, personally, I find this amazingly unnatural. As a side-effect of the @Transaction(REQUIRED) declaration and call to em.isOpen() on commitAllChanges(), the persistence context gets flushed and all the work you did outside of transactions in previous method calls gets committed.
But the bigger problems are:
Learn more about Weld...
No, it won't be in JPA2. Perhaps in JPA 2.1 I might be able to talk people into supporting some kind of compromise solution using something like this:
@Stateful @ConversationScoped @Transaction(OPTIMISTIC) public class OrderConversation { @PersistenceContext(type=EXTENDED) EntityManager em; @Current Conversation conversation; @Current OptimisticTransaction optimisticTransaction; private Order order; public Order getOrder() { return order; } public void load(int id) { conversation.begin(); optimisticTransaction.begin(); order = em.get(User.class, id); } public void addLineItemByAjax(Product product, int quantity) { order.addLineItem( new LineItem(product, quantity) ); } public void removeLineItemByAjax(LineItem li) { order.removeLineItem(li); } public void commitAllChanges() { optimisticTransaction.commit(); conversation.end(); } }It doesn't quite give you everything you have with FlushMode.NEVER but it might be acceptable to Oracle who, as far as I know, are the only folks objecting to this feature.
Learn more about Weld...
So, basically your initial example is not really an example on what is so good about FlushMode.MANUAL (because there is a counter example, you wrote it yourself) that shows that theres is an alternative way of doing the same thing... So I ask again, can you show me an example that actually shows how the persistence context propagation gets broken by not using FlushMode.MANUAL? An example that could be shown to someone in the EclipseLink team with the message: and that would leave them baffled.
Ok, so, FlushMode.MANUAL is a shortcut to to basically the same thing an extended persistence context do? Nice but, shouldnt we prefere the standard solution (like Seam did by preferring JSF over Wicket ;-) )
And why is that? Does this mean that extended persistence contexts can only be used in Stateful EJBs? and why it can not be fixed by altering the way extended persistence contexts work but without creating FlushType.MANUAL? What do the guys of EclipseLink do when someone reports this as a bug or as requested feature? Has anyone tried that? Does this mean that extended persistence contexts are actually a feature of stateful EJBs and not a feature usable from Seam POJOs(Specially not the stateless ones) or from a JSE application? )
I also said something similar to the EclipseLink guys, and this was the answer. If I am going to get inconsistencies between requests, maybe I do not care about getting them between query calls... if that is the case... does that mean that FlushMode.MANUAL is useless for me?
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
Huh, I just told you what can't be done, I'm sure you have enough knowledge of this stuff to figure out the rest yourself. It's not my job to write examples to help the EclipseLink team improve their product!
But here's a starting point for the kind of things I'm thinking about:
@Stateful @ConversationScoped public class OrderConversation { @Current OrderDao orderDao; @Current ProductDao productDao; @Current Conversation conversation; private Order order; public Order getOrder() { return order; } public void load(int id) { conversation.begin(); em.setFlushMode(MANUAL); order = orderDao.find(id); } public void addLineItemByAjax(in productId, int quantity) { Product product = productDao.find(productId); order.addLineItem( new LineItem(product, quantity) ); } public void removeLineItemByAjax(LineItem li) { order.removeLineItem(li); } public void commitAllChanges() { em.flush(); conversation.end(); } } @Stateless OrderDao { @PersistenceContext EntityManager em; public Order find(int id) { return em.find(Order.class, id); } } @Stateless ProductDao { @PersistenceContext EntityManager em; public Product find(int id) { return em.find(Product.class, id); } }In this example, the persistence context propagates to the XxxxxDaos, so the Order and the Product belong to the same persistence context, and remain attached to it for the entire optimistic transaction. If you try to use Transaction(NOT_SUPPORTED), this will not be the case. The Order will not be attached when commitAllChanges() is called, and the LineItem changes will not be persisted. I don't think you will be able to rewrite this example without FlushMode.MANUAL.
Learn more about Weld...
No. I explained that to you. Please try reading and understanding before arguing. Geez.
You can find the answer to this question and more in the JPA 1.0 specification.
Whatever change you would make would be more or less functionally equivalent to FlushMode.MANUAL. Of course you could call it FooBar.IM_BEING_REALLY_DENSE if you prefer.
I have no idea. Why are you asking me what EclipseLink users do?
You can find the answers to these questions and more in the JPA 1.0 specification and the Seam documentation.
I just told you about the problem with persisence context propagation but you decided to deliberately not understand what I was explaining.
Learn more about Weld...
Note that I'm not advocating that this is a great solution. I don't think it's better to introduce a whole new kind of transaction notion in EE and then have to define its demarcation and propagation rules than to introduce a new FlushMode. The new FlushMode is a far simpler solution.
Learn more about Weld...
Well, it seems to me like it would be a nice idea to make those Oracle guys accept FlushMode.MANUAL in to the JPA spec, and I way to that would be to submit a bug in to EclipseLink bugtracker, asking for a way to do something that can only be done with FlushMode.MANUAL, that way they would be forced to implement a comparable solution (or even just accept to add FlushMode.MANUAL to the spec). That is, of course, if they do not dismiss bug without reading and understanding before rejecting them. Geez. :-P
Yes you told me about the problem with persisence context propagation, but I was hoping for a concrete example, you just told me but did not explain me why it breaks. If you have a link or know a book with a guide that explains why it breaks, that would be good enough for me, but it really be great if you could explain it and provide an example.
Please do not get me wrong, I really appreciate that you take time to answer this questions in this forum, I know you are one of the greatest experts in this stuff, but sometimes you do exactly what you are accusing me of doing, you just start arguing without reading carefully and without trying to see it from the POV of someone without all your knowledge.
OTOH maybe its my Karma from all the times I have been dismissive with people with less knowledge than me... :'(
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
Oh, I see that you did provide an example, see, I knew you could no really be a bad guy :-D
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
I posted a link to this discussion in the EclipseLink mailing list, and got this answer:
So, it seems that can be used to achive conversational behavior... and all without support of FlushMode.MANUAL... If course asked him in return:
But he still has not responded...
What I would really like to understand is if FlushMode.MANUAL actually makes it possible to integrate conversational behavior with persistence in a way that is really impossible to achieve without it, or it is more like a much more convenient way to do things that are possible anyway.
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
There is no persistence context propagation for application-managed EntityManagers, of course! Nor is there when there is no JTA transaction active.
Learn more about Weld...
Isn't that what extended container-managed PCs were designed to handle? They are scoped to the lifetime of a SFSB, not just one method/tx. And the SMPC in Seam is conversation-scoped, thus you can use it for multiple SFSBs or JavaBeans, not just one.
I don't understand why he's recommending application-managed EntityManagers. Typically it's recommended to use container-managed EntityManagers in JEE envmts.
In any event, GKing is correct as per section 5.7 of JPA 2.0 spec:
However, the spec does state:
Plus, who wants to do trivial stuff like em.close();? Isn't that what the container is for???
required reading: Scala and more Scala... www.artima.com
Mmmm, I wonder what is the real difference between a container-managed EntityManager and an application managed one, after all, WebBeans should allow me to store any object at the conversation context... why shouldn't it allow me to store an application managed EntityManager ?. And use EntityManager transactions to commit when I desire to do so. It of course wouldn't care about JTA, but isn't FlushMode.MANUAL a way to JTA commits until we decide to not ignore them anymore? And for that, according to Sutherland I can use joinTransaction().
I am not saying this is a better solution than FlushMode.MANUAL, it does sound more cumbersome, I am just saying that from a practical POV it could achieve the same effect.
Of course nobody wants to deal with that stuff, and of course FlushMode.MANUAL in combination with Seam is a lot more comfortable than doing what the EclipseLink guys says is the way of dealing with this problem, that is not what I am discussing here, what I want to understand (again) if it is plain impossible to do this without FlushMode.MANUAL, or if FlushMode.MANUAL is a convenience api sugar (and I love api sugar, but I like to know when I am using it)
For example what if I where to write (wouldn't this give me an application managed entity manager that would work with its own entitymanager transactions until I decided to join the JTA transaction using joinTransaction() and effectively (but cumbersomely) emulate FlushMode.MANUAL?):
@Produces @ConversationScoped public EntityManager getPaymentStrategy() { return EntityManagerFactory.createEntityManager(); }And then inject the conversation-scoped PC like this:
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog
Sorry, made a copy & paste mistake (posted getPaymentStrategy instead of getTheConversationScopedEntityManager), here comes again:
For example what if I where to write (wouldn't this give me an application managed entity manager that would work with its own entitymanager transactions until I decided to join the JTA transaction using joinTransaction() and effectively (but cumbersomely) emulate FlushMode.MANUAL?):
@Produces @ConversationScoped public EntityManager getTheConversationScopedEntityManager() { return EntityManagerFactory.createEntityManager(); }And then inject the conversation-scoped PC like this:
Please don't forget to rate!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint Exupéry
Please visit my blog