is there a possibility to execute an sql script, after EclipseLink generated the ddl?
In other words, is it possible that the EclipseLink property "eclipselink.ddl-generation" with "drop-and-create-tables" is used and EclipseLink executes another sql-file (to insert some data into some tables just created) after creating the table definition?
I'm using EclipseLink 2.x and JPA 2.0 with GlassFish v3.
Or can I init the tables within a java method which is called on the project (war with ejb3) deployment?
I came across this question for the same reasons, trying to find an approach to run an initialization script after DDL generation. I offer this answer to an old question in hopes of shortening the amount of "literary research" for those looking for the same solution.
I'm using GlassFish 4 with its default EclipseLink 2.5 JPA implementation. The new Schema Generation feature under JPA 2.1 makes it fairly straightforward to specify an "initialization" script after DDL generation is completed.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="cbesDatabase" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:app/jdbc/cbesPool</jta-data-source>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata"/>
<property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
<property name="javax.persistence.sql-load-script-source" value="META-INF/sql/load_script.sql"/>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
The above configuration generates DDL scripts from metadata (i.e. annotations) after which the META-INF/sql/load_script.sql script is run to populate the database. In my case, I seed a few tables with test data and generate additional views.
Additional information on EclipseLink's use of JPA's properties can be found in the DDL Generation section of EclipseLink/Release/2.5/JPA21. Likewise, Section 37.5 Database Schema Creation in Oracle's Java EE 7 Tutorial and TOTD #187 offer a quick introduction also.
Have a look at Running a SQL Script on startup in EclipseLink that describes a solution presented as a kind of equivalent to Hibernate's import.sql feature1. Credits to Shaun Smith:
Running a SQL Script on startup in EclipseLink
Sometimes, when working with DDL
generation it's useful to run a script
to clean up the database first. In
Hibernate if you put a file called
"import.sql" on your classpath its
contents will be sent to the database.
Personally I'm not a fan of magic
filenames but this can be a useful
feature.
There's no built in support for this
in EclipseLink but it's easy to do
thank's to EclipseLink's high
extensibility. Here's a quick solution
I came up with: I simply register an
event listener for the session
postLogin event and in the handler I
read a file and send each SQL
statement to the database--nice and
clean. I went a little further and
supported setting the name of the file
as a persistence unit property. You
can specify this all in code or in the
persistence.xml.
The ImportSQL class is configured as
a SessionCustomizer through a
persistence unit property which, on
the postLogin event, reads the file
identified by the "import.sql.file"
property. This property is also
specified as a persistence unit
property which is passed to
createEntityManagerFactory. This
example also shows how you can define
and use your own persistence unit
properties.
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.SessionEvent;
import org.eclipse.persistence.sessions.SessionEventAdapter;
import org.eclipse.persistence.sessions.UnitOfWork;
public class ImportSQL implements SessionCustomizer {
private void importSql(UnitOfWork unitOfWork, String fileName) {
// Open file
// Execute each line, e.g.,
// unitOfWork.executeNonSelectingSQL("select 1 from dual");
}
#Override
public void customize(Session session) throws Exception {
session.getEventManager().addListener(new SessionEventAdapter() {
#Override
public void postLogin(SessionEvent event) {
String fileName = (String) event.getSession().getProperty("import.sql.file");
UnitOfWork unitOfWork = event.getSession().acquireUnitOfWork();
importSql(unitOfWork, fileName);
unitOfWork.commit()
}
});
}
public static void main(String[] args) {
Map<String, Object> properties = new HashMap<String, Object>();
// Enable DDL Generation
properties.put(PersistenceUnitProperties.DDL_GENERATION, PersistenceUnitProperties.DROP_AND_CREATE);
properties.put(PersistenceUnitProperties.DDL_GENERATION_MODE, PersistenceUnitProperties.DDL_DATABASE_GENERATION);
// Configure Session Customizer which will pipe sql file to db before DDL Generation runs
properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, "model.ImportSQL");
properties.put("import.sql.file","/tmp/someddl.sql");
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("employee", properties);
}
I'm not sure it's a strict equivalent though, I'm not sure the script will run after the database generation. Testing required. If it doesn't, maybe it can be adapted.
1 Hibernate has a neat little feature that is heavily under-documented and unknown. You can execute an SQL script during the SessionFactory creation right after the database schema generation to import data in a fresh database. You just need to add a file named import.sql in your classpath root and set either create or create-drop as your hibernate.hbm2ddl.auto property.
This might help as there is a confusion here:
Use exactly the same set of properties (except logger) for data seeding.
DO NOT USE:
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
DO USE:
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata"/>
<property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
I confirm this worked for me.
:) Just substitue with your data
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata-then-script"/>
<property name="javax.persistence.sql-load-script-source" value="META-INF/seed.sql"/>
It is called BEFORE ddl-execution. And there seems to be no nice way to adapt it, as there is no suitable event one could use.
This process offers executing sql before DDL statments whereas what would be nice (for example, to insert seed data ) is to have something which executes after DDL statements. I don't if I am missing something here. Can somebody please tell me how to execute sql AFTER eclipselink has created tables (when create-tables property is set to tru)
Related
When I try to persist an entity to the database, I get the error in the subject line. I have it in the persistence.xml along side my other classes, which happen to work and persist.
I know this question has been asked many times but each time it seems to have a different cause. I tried the suggestions elsewhere. If nothing else you can shed light on a mystery for me. I am pretty new to Java as well as anything Inversion of Control.
My Transaction is a valid class. Trust me when it works. It works in every sense- rendering the result of its' computation to the jsp page, even sending it to pubsub and unpacking it when it returns. It simply doesn't work when I try to persist it through a DAO (entity manager).
#Entity
public class Transaction {
#Id
String uuid;
#Transient
Wallet senderWallet; // should this be transient? Can it be?
#Column(name = "address")
String recipientAddress;
double amount;
#Transient
HashMap<String, Object> output; // like basic receipt
#Transient
HashMap<String, Object> input; // like wire transfer document
I made a lot of this transient just to exclude what could be wrong.
I strongly suspect it has something to do with higher level configuration and structure. I am new to Java and these types of frameworks in general but I would guess that we should be seeing a Transaction.class file in the bin folder, correct? You can see we do not.
Yet it's obviously being compiled and run, because I am building transactions all the time in my experimentation code. Something is funny about this, so if we can solve the persistence issue, great, but to learn something about what's going on in bin would be great. I am willing to do a refactor/overhaul of my structure and configuration if it requires it. In fact I am looking forward to it. I was told also I should be using beans like #service and #repository. I am using #Entity and #Controller. We were taught JDBC and then JPA first and second and then spring and making beans, but by that time I already started the project and my mind was still remembering and trying to digest the earlier stuff, so I have not made these types of beans. I might have some tight coupling in different places that I can fix but my first priority is getting Transaction persisting. Other entities persist no problem and the class itself works and I see nothing special about this one. I have tried various permutations but in particular, should I not see Transaction.class files?
I see all my class files for every single thing used in my Target folder. That's a maven folder that is sibling of src and bin, and seems to be used for making artifacts. Might I have been running my code through that and certain entities are invisible to spring but visible to eclipse/tomcat? If so how to correct? I am only guessing wildly
Edit:
Here is a class that is persisting fine:
#Entity
public class User {
#Id
String username;
String password;
String hint;
String answer;
String email;
#Embedded
WalletForDB wallet;
Here's my persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="Case Study">
<class>privblock.gerald.ryan.entity.Transaction</class>
<class>privblock.gerald.ryan.entity.Account</class>
<class>privblock.gerald.ryan.entity.Block</class>
<class>privblock.gerald.ryan.entity.Blockchain</class>
<class>privblock.gerald.ryan.entity.User</class>
<class>privblock.gerald.ryan.entity.WalletForDB</class>
<properties>
<!-- DB configuration -->
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/blockchain" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.driver"
value="com.mysql.cj.jdbc.Driver" />
<property name="javax.persistence.jdbc.password"
value="root" />
<!-- EclipseLink configuration -->
<property name="eclipselink.logging.level" value="FINEST" />
<property name="eclipselink.ddl-generation"
value="create-or-extend-tables" />
</properties>
</persistence-unit>
</persistence>
BTW my configuration is now broken, as I tried to make my folder structure like Maven/Spring conforming and I cleaned and updated project. For some reason the combination of Tomcat, Spring, Maven and Eclipse is not working. I don't know which, I don't know if I'm close but that's a separate problem.
I have issue with Hibernate query, my IDEA inspection error syntax:
This inspection controls whether the Persistence QL Queries are
error-checked
But I create mapping for Task objects in my hibernate.cfg.xml:
<session-factory>
<property name="connection.url">jdbc:postgresql://localhost:5432/todo_list</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.username">postgres</property>
<property name="connection.password">1</property>
<property name="dialect">org.hibernate.dialect.PostgreSQL95Dialect</property>
<mapping resource="ru/pravvich/model/Task.hbm.xml" />
</session-factory>
Facets:
If I cheating IDE and instead createQuery("select t from Task t"), create variable and push in createQuery
String hql = format("select t from Task t where t.id > %s", 0);
session.createQuery(hql)
It's work, but it's not normal code. How to fix this issue
Here is what for me resolve the same issue:
Open in the IDEA Preferences (Settings)/Editor/Language Injections and under the list of languages find Session (org.hibernate).
Under the column Language, it should be selected Hibernate QL.
Double click on it and a list of operations will be displayed.
Select the operations that you need.
IDEA doesn't recognise which or what Descriptor you are using. Check Project Structure -> Facets -> Hibernate. You should have found a cfg.xml file in Descriptors. If you are using package scanning through spring session factory definition,you should have found a session factory bean. If neither of them exists,you may add one.
I was looking over some code that I created awhile ago, and noticed something odd.
I am creating a Persistence Unit programmatically due to needed user input as to the location of the Database to read.
My code is as follows
Map properties = new HashMap();
db = plan.db;
// Configure the internal EclipseLink connection pool
properties.put(TRANSACTION_TYPE, PersistenceUnitTransactionType.RESOURCE_LOCAL.name());
properties.put(JDBC_DRIVER, "net.ucanaccess.jdbc.UcanaccessDriver");
properties.put(JDBC_URL, "jdbc:ucanaccess://" + db + ";singleconnection=true;memory=true");
properties.put(JDBC_USER, "");
properties.put(JDBC_PASSWORD, "");
// properties.put( "provider" , "org.eclipse.persistence.jpa.PersistenceProvider");
EntityManagerFactory emf2;
EntityManager em2;
emf2 = Persistence.createEntityManagerFactory("PU", properties);
em2 = emf2.createEntityManager();
With this I was able to create my connections multiple times.
The problem I noticed is that I also had code in my "Persistence.xml"
<persistence-unit name="PU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>db.Items</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url" value=""/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.driver" value="net.ucanaccess.jdbc.UcanaccessDriver"/>
<property name="javax.persistence.jdbc.password" value=""/>
</properties>
Now I noticed that I cannot find any way to add an "Entity Class" to this "Persistence Unit," however I was able to run my code fine, just like this.
I'm curious if it just overwrites the old properies and such from the Persistence Unit of the same name? It still uses the Persistence Class of "db.Items."
I just want to make sure that this is the correct way to do it.
I'm doing changes to my code, so I cannot run it currently to see if I delete everything in my PErsistence.xml what will happen, but I'm curious about this.
I also noticed that the "provider" property was commented out. Do I need that posted? (It's included in the xml file).
there is also an example I saw that mentioned about "Server target" being set to "no" or something? Any comments on that?
Thanks all
It overwrites the properties you have specified in persistence.xml. You can for example only set user name and password in this way and the other properties will be used as defined in the file. If it's "right" to do it this way I don't know, but I have done the same.
The call to Persistence.createEntityManager(unit, props) starts with searching for the named unit in any persistence.xml found in the classpath. Then properties from props are added or overwritten to the properties read from file for that unit.
I have no comment about your other questions.
How can I set openJPA cache so that it works only for chosen entities, maybe I need use some annotaion over they?
my persistence.xml contains:
<property name="openjpa.DataCache" value="true"/>
<property name="openjpa.RemoteCommitProvider" value="sjvm"/>
but thats settings works for all my entities(tables), so i want to cache for example only that table:
#Entity(name = "IsoCountryCodes")
#Table(name = "ISO_COUNTRY_CODES", schema = "ANALYSIS")
#DataCache(timeout=120000)
public class IsoCountryCodes implements Serializable{
....
}
But #DataCache doesnt fix it, its only set the timeout of cache saving.
UPDATE:
I cannot use openJPA 2.0 cause my project deployed on WebLogic 10.36 and have provided KODO openJPA 1.3.
Also i try to include only chosen entities by adding property:
property name="openjpa.DataCache" value="true(Types=foo.bar.FullTimeEmployee)"
but got this error:
org.apache.openjpa.lib.util.ParseException: There was an error while setting up the configuration plugin option "DataCache". The plugin was of type "class kodo.datacache.KodoConcurrentDataCache". The plugin property "Type" had no corresponding setter method or accessible field. All possible plugin properties are: [CacheSize, EvictionSchedule, FailFast, NAME_DEFAULT, Name, SoftReferenceSize].
Can you help me?Maybe you know other ways to exclude or include entitites from caching, maybe with Ehcache usage?
<property name="openjpa.DataCache" value="true"/>
That enables the L2 cache for all Entities. If you are using jpa-2.0, try adding <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> to turn the cache on. Also, replace the #DataCache annotation with a #javax.persistence.Cacheable annotation.
I'm looking for easy way to check inconsistency between entity and table for my JPA application.
After changing table definition (ex. column name, type, add new column, delete column), I sometimes forget to change entity definition.
So I'd like to be notified if entity and table definitions are inconsistent.
Is some tool available? Eclipse plugin is preferable, but others are also considerable.
I know Dali. But this tool does not suit for me because I should modify Dali output.
(I'm using class inheritance as this question, and so on.)
Your JPA implementation should provide a property on persistence.xml to make it for you. By example, Hibernate provides hibernate.hbm2ddl.auto property which allow to create the schema, update or just validate.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence ...>
<persistence-unit ...>
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- ... -->
<!-- ... -->
<property name="hibernate.hbm2ddl.auto" value="validate"/>
This makes the schema validation process on EntityManager initialization.
Check on your current JPA implementation documentation to find the equivalent property.
Good luck!