If you need predictable access to triggers and other stored procedures, you can't use JPA and be portable. That stated, there are a few tricks which may help...
[Triggers] Let's divide triggers into three categories: 1. Triggers that only modify internal data (i.e. data is not exposed through any JPA entities). These triggers are safe but, because JPA flushes the SQL calls at will, you cannot rely on them being called at a specific time. For situations, such as recording who modified a record and when, this would seem to be a perfectly safe technique...but there is a real danger that a developer in future will extent the entity to cover the previously internal fields. 2. Triggers that modify entity data within a table. Here, the JPA cache will be out of sync with the database. This can be acceptable if you make the JPA calls, then call flush() to trigger the SQL statements, and then call merge() on any modified entities to refresh the cache. It is safe to say that this is NOT RECOMMENDED and can lead to problems if merge() is not called. 3. Triggers that modify entity data across multiple tables. DANGER. Because the sequencing of the SQL is not under developer control, you cannot rely on this safely working. Don't do it. In other words, I do not believe that database triggers should be used with JPA. Thankfully, JPA 2.0 attempts to define a replacement for triggers. These are called the lifecycle callbacks (see section 3.5 of JPA 2.0). These appear to be useful for simple cases, but I've found them inappropriate for more complex operations. The specification places a significant limitation on what can be done in a lifecycle callback: > In general, the lifecycle method of a portable application should not invoke > EntityManager or Query operations, access other entity instances, or modify > relationships within the same persistence context. A lifecycle callback > method may modify the non-relationship state of the entity on which it is > invoked. More on this later. [Stored Procedures / SQL functions / DB-specific functions] Native Queries are your answer. An unfortunate reality of JPA 2.0 is that any query that needs access to a function not contained in JPQL MUST be turned into a native query. This is a significant weakness of JPA in my not so humble opinion. I would love to see a mechanism in JPA 3.0 which allows the author to define aliases within JPQL for stored procedures, SQL functions, or DB-specific functions. This would then reduce porting to updating those aliases rather than updating all the individual native queries. I recommend defining a <mapping-file> within your persistence.xml in which as many of the native queries are defined as possible. This allows the code to access the queries by name and simplifies the task of finding and migrating all the native queries. [My Wish and a Use Case] I have an entity which I'll call MagazineArticle. The entity might look something like this (getters / setters omitted for brevity): @Entity @Table(name="magazine_articles") public class MagazineArticle { @SequenceGenerator(name="ArticleIdGenerator", sequence="article_id_gen") @Id @GeneratedValue(generator="ArticleIdGenerator", strategy=Generator.Type.SEQUENCE) private long id; private String title; private String author; private String body; // NOTE: Getters / Setters omitted for brevity @ElementCollection(fetch=FetchType.EAGER) @CollectionTable(name="article_figures", joincolum...@joincolumn(name="article_ref")) private Collection<Figure> figures; } Hidden the entity but contained within the 'magazine_articles" table is a DB-field which is used for text search operations. The contents of this field are generated from content within the article entity (e.g. title / author / body) and from data in other tables (e.g. article_figures). Optimally, the contents would be generated within the database whenever the entity is created or updated without action from JPA. However, because the sequence of database operations is hidden and MagazineArticle would probably be flushed before the Figures, I do not believe that a trigger on MagazineArticle can be safely used. One might then consider a @PostUpdate and @PostPersist callback, but the JPA 2.0 specification recommends against EntityManager or Query operations. So this is out. Instead, a combination of JPA and a NativeQuery appears to be necessary. em.persist(article); em.flush(); // to write out MagazineArticle and associated Figures. Query query = em.createNativeQuery("SELECT generate_article_index(?1)"); query.setParameter(1, article.getId()); query.getSingleResult(); // generate the index em.flush(); em.refresh(article); // not strictly necessary but recommended Not quite as smooth as a trigger, but it works. Search operations naturally benefit from having the index. Query query = em.createNamedQuery("FindArticle); query.setParameter(1, searchTerms); List<Articles> results = query.ResultList(); Here the 'FindArticle' query is referenced from the persistence.xml file. But this is a simple search operation. Why shouldn't we be able to use JPQL instead? Why not call Query query = em.createQuery("SELECT a,calculate_search_rank(a) AS score FROM MagazineArticle a WHERE article_matches_terms(:terms) ORDER BY score DESC"); query.setParameter("terms", searchTerms); List<Articles> results = query.ResultList(); where the 'calculate_search_rank' and 'article_matches_terms' are aliases which get converted into SQL at the last minute? I would expect these aliases to be defined either within persistence.xml or within the <mapping-file>. With this simple change, many situations currently requiring native queries can migrate to JPQL queries. On Jun 3, 2010, at 4:34 AM, Jean-Baptiste BRIAUD -- Novlog [via OpenJPA] wrote: > Hi, > > Is there a way to use JPA abstraction from Java code to manipulate database > instances, triggers, stored procedure ? > > Before going to the complex scenario, simple things first : How can I create > a database instance in a Java way : "dev once, run everywhere" ? > > I had to write some SQL to create a MySQL database empty instance from Java > code but that code is not portable now. > > Any thoughts ? > > Ps : more complex scenarios : need to manage triggers, how can I create, > update and delete it in a portable manner ? > > View message @ > http://openjpa.208410.n2.nabble.com/JPA-for-portable-database-management-tp5134215p5134215.html > > To start a new topic under OpenJPA Users, email > ml-node+208411-1595610943-93...@n2.nabble.com > To unsubscribe from OpenJPA Users, click here. > -- View this message in context: http://openjpa.208410.n2.nabble.com/JPA-for-portable-database-management-tp5134215p5136127.html Sent from the OpenJPA Users mailing list archive at Nabble.com.