I annotated a bunch of POJO's so JPA can use them to create tables in Hibernate. It appears that all of the tables are created except one very central table called "Revision". The Revision class has an #Entity(name="RevisionT") annotation so it will be renamed to RevisionT so there is not a conflict with any reserved words in MySQL (the target database).
I delete the entire database, recreate it and basically open and close a JPA session. All the tables seem to get recreated without a problem.
Why would a single table be missing from the created schema? What instrumentation can be used to see what Hibernate is producing and which errors?
Thanks.
UPDATE: I tried to create as a Derby DB and it was successful. However, one of the fields has a a name of "index". I use #org.hibernate.annotations.IndexColumn to specify the name to something other than a reserved word. However, the column is always called "index" when it is created.
Here's a sample of the suspect annotations.
#ManyToOne
#JoinColumn(name="MasterTopID")
#IndexColumn(name="Cx3tHApe")
protected MasterTop masterTop;
Instead of creating MasterTop.Cx3tHApe as a field, it creates MasterTop.Index. Why is the name ignored?
In case this helps anybody, this happened to me today and it turned out I was using a reserved word on my entity definition:
#OneToMany(mappedBy="list")
#OrderColumn(name="order")
private List<Wish> wishes;
"order" in this case, and Hibernate just skipped over this class. So check your user defined names! :)
Cheers,
Mark
Answer to your side question (What instrumentation can be used to see what Hibernate is producing and which errors?)
You can org.hibernate.tool.hbm2ddl.SchemaExport to generate your tables.
AnnotationConfiguration conf = (new AnnotationConfiguration()).configure();
new SchemaExport(conf).create(showHql, run);
The first argument allows you to see which HQL this command generates (CREATE TABLEs etc). The second one is whether it should actually perform any modifications (ie false = dry-run).
So running it with (true, false) will show you exactly what Hibernate would do to your tables, without changing anything.
name attribute on #Entity is not what you want to use for this purpose. Use #Table annotation instead:
#Entity
#Table(name="RevisionT")
public class Revision {
It is due to column names matches with your underlying Database sql reserved words.....try by changing name of columns.....i had faced same problem by changing names it did work.
For me it was a syntax mistake in columnDefinition. Easily detectable by the debug logs.
Perhaps you're using the wrong annotation. Once I accidentally annotated an entity with #org.hibernate.annotations.Entity instead of #javax.persistence.Entity, and Hibernate just skipped it.
Put hibernate.show_sql config property to true and see if Hibernate generated the create table code. If so, copy the create statement into your database client (ui or command line) and see if your database returns an error.
For me the error was not apparent until I did so.
I used the field name 'condition' which was a reserved MySQL word.
So check your field names...
Related
I'm using Spring Boot 2.6.4 and Java 17. And I previously had an Entity called BlogPostComment but recently decided that just Comment is more concise. I don't have a data.sql file to explicitly create tables and let Hibernate handle all the database operations for me. So I'm expecting that the table previously named blog_post_comment would be renamed as comment. However, when I rerun my application after renaming the entity, Hibernate creates two tables blog_post_comment and comment instead of just the latter.
Before renaming:
#Entity
public class BlogPostComment { ... }
After renaming:
#Entity
public class Comment { ... }
I've tried adding #Table(name = "comment") annotation to this entity, but Hibernate created the table with the old name all the same. And I've also tried invalidating IntelliJ IDEA caches, still did not solve this problem. Please help me identify the cause of this error, thank you.
It is possible that your hibernate.hbm2ddl.auto property in application.properties is set to none . What none does is that no action is performed. The schema will not be generated. Hence your changes will appear as a new table in your database. What you should do then is to set the property to update and then run the application. What update does is that the database schema will be updated by comparing the existing database schema with the entity mappings.
PS: If no property is defined, the default property is none. You should add the property and set to update
I strongly doubt that Hibernate creates a blog_post_comment table after you renamed the entity. I suspect this is just still around from the previous run.
Hibernate (or any other JPA implementation) does not know about you renaming the entity. It has no knowledge what so ever about the entities present during the last start of the application. Therefore it doesn't know that there is a relationship between the existing blog_post_comment table in the database and the not yet present comment table it is about to create.
When Hibernate "updates" a schema it checks if a required table already exists and if so it modifies it to match what is required by the entities. But even then it won't rename columns, it would just create new ones.
In generally you should use Hibernates schema creation feature only during development and never for actually deploying a schema into production or even worse, updating a schema in production. For this you should use specialised tools like Flyway or Liquibase which exist for exactly this purpose.
I am working with Java EE 7 on a Wildfly server. I have a strange scenario, where the client has two tables - "employees" and "employees_modified". The second table has the exactly same structure as the first one and servers as a modification storage. So if an employee changes his name from "john" to "john-1", we will write to employees_modified
insert into employees_modified(first_name) values("john")
Please note that the other fields in the table "employees_modified" are empty.
The question is: is there a way to somehow map the two tables and overwrite the values from employees by those in employees_modified where they are present.
I looked at #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) and #AttributeOverrides but those solutions don't seem to fit to my scenario.
Look at hibernate envers, it solves your problem simply. Attach envers to your project. Place the first table under audit with annotation #Audited and #AuditTable(value = "employees_modified"). But as pointed by #Predrag Maric it is important to leave other fields of the second table empty, you can use #PostPersist (or listener in pure hibernate) method in entity. In this method you can describe additional logic employees_modified entity creation and persisting.
You can use #SQLUpdate and #SQLDelete to customize the CRUD statements to be redirected to a different table:
#Entity
#SQLUpdate( sql="UPDATE employees_modified SET name = ? WHERE id = ?")
#SQLDelete( sql="DELETE FROM employees_modified WHERE id = ?")
public class Employees {
...
}
If it's only for auditing, I agree with the answers before me (triggers, events etc).
If you actually want to access that "employees_modified" table (e.g. run complex Hibernate queries) than you can use a second persistent unit. The following post: https://developer.jboss.org/thread/237078 seems to indicate that's a recommendation from hibernate. Obviously the 2nd unit will need xml configuration rather than annotation - at least it can't rely on the same #Table annotation.
BTW there's also some documentation about a #SecondaryTable annotation, but it's my understanding that it doesn't match your case (because your business probably needs to treat those tables differently - sometimes you want to view just the history, sometimes just the live data)/
We are creating a new web application backed by JPA to replace an old web application. As part of the migration we are converting the old application's database to a new, more sophisticated, JPA-managed database.
So I've written a 'script' that converts the old database to a set of JPA entities and subsequently saves them. It works like this:
Create an order of conversion based on the dependencies of the domain models
For each entity
Execute database query to legacy DB
Store new object for each obtained table row in a list in memory
Iterate over generated lists in the same order as the conversion, and persist each entity.
Now, the first two steps work well. Upon persisting, however I get an exception. The exception occurs when one entity has a relation to another entity. For example if one of our entities would be a Book and another would be Chapter defining a #ManyToOne(optional=false) relation to Book. Upon persisting the Chapter, it throws the exception java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: models.Chapter.book -> models.Book.
Of course, this indicates that something is wrong with the state of the book: it seems it is either not set or has not yet been persisted. However, I can verify that the Book is set properly in the conversion of the Chapter, and I can also verify that all entities of type Book are persisted by the EntityManager before the entities of type Chapter get persisted. Obviously, my JPA provider does not behave as expected and does not truly persist my Book objects for some reason.
What solution would allow me to save the entire graph of objects that I have converted to the database? I use Hibernate as my JPA provider and I also use Spring 3.1 for injection of dependencies and EntityManagers.
EDIT 1: Some additional info: I've again verified that entityManager.persist() is called on each of the book objects before entityManager.persist() is called on the chapters. However, the id of the book object remains null, meaning it is not properly persisted. The database also remains empty, despite not using transactions.
EDIT 2: Because I don't think it's clear from the text above: the Book and Chapter story is just an example. It happens for any entity that references another entity. This makes it seem as if I'm not using JPA/Hibernate properly as opposed to not setting the values of my entities properly.
EDIT 3: The core issue seems to be that despite persisting Book properly, having all the right annotations, book.getId() remains null. Basically, Hibernate is not setting the ids on my entities after persisting them, leading to problems when I need to use those entities later.
I once battled with such an error from hibernate myself. It turned out that it was a combination of a circle in the object graph and the cascade settings that caused the problem.
It has been a while so the fowlling might not be 100% accurate but maybe it is enough information to track your problem:
Hibernate Wants to insert the chapter. Realizes it needs to insert the book first.
Wants to insert the book. Realizes it needs to insert another entity first (e.g. publisher)
Inserts publisher and performs cascades defined on publisher (e.g. authors)
Author has e.g. reference to his lastestBook. Because hibernate internally already marked the book as processed (in step 2) you would no get an exception stating that author.book references a transient instance.
To find out if this is your problem you can enable full hibernate debugging and follow the path hibernate is taking through your object graph.
I've found the answer thanks to the discussion I've had with user1888440.
The solution to this answer was that the Spring #Transactional annotation was nonfunctional in my application. This mean that everything Hibernate did didn't occur in the context of a transaction. This meant that Hibernate would not set ids after persisting and this meant that all conversions would break down.
The reason why #Transactional did not work is probably because of a fact I did not mention: this script is part of a Play 2.0 (actually 2.1) app and is thus built using SBT. SBT doesn't use a normal Java setup to build an application, but instead uses the Scala compiler to compile Java as well. My guess is that the Scala compile did not work well with the AspectJ that Spring requires to make #Transactional work.
Instead, I performed all of the database work involved in this conversion within a programmatically defined Spring transaction (section 11.6). Now everything behaves as expected.
Check he unsaved values for your primary key/Object ID in your hbm files.If you have automated ID creaion by hibernate framework and you are stting th ID somewhere it woudl throw this error.By defaut the unsaved-value is 0 , so if you set the ID as 0 you would see this error.
Sounds like you are forgetting to assign a Book to each Chapter before persisting it. Even if you have persisted the Book it needs to be assigned to the #book property of the Chapter instance before you can persist the Chapter. This is because you have specified the relationship as non-optional. #book can never be null.
I have a small schema consisting of ~10 classes mapped by jpa2 with hibernate as provider. All of the classes are build in the same basic way (#Entity annotation for the class, id with #Id and #GeneratedValue). All classes have default constructors and default getter/setters.
All but one of the classes are in a relation to one another (via associations or inheritance). And this one class does not get a database table created in the database during the schema generation process.
I've tried the following settings with hbm2ddl.auto:
create: All tables but the one are created. When the entity is accessed for the first time an exception is thrown: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table '...' doesn't exist (or the oracle equivalent if the code is run on Oracle DB).
validate: hibernate complains about the missing table during schema validation.
update: The table does not get created and an exception (like with create) is thrown the first time an entity of that class is accessed.
Has anyone any idea on this?
Try the following: modify the class of that Entity to only have the id field. Make sure the class is annotated with #Entity at the id field is annotated with #Id. Make sure this entity is declared in the list of mapped-classes (or is in a package that is declared amongst the mapped packages). Add "TRACE" level logging to "org.hibernate" via log4j.xml. Start a hibernate session (start your app), and look in the log for the statements Hibernate generates for the creation of the schema. If the table is missing from there, then you're not configuring the bean correctly and hibernate is not considering it as being part of the model. If the sql for the creation of the corresponding table is there, but there's an error when it's executed, see what that SQL actually contains, this might help you find out what hibernate doesn't like. When the "empty" bean is finally created, start adding the properties/associations to it one at a time and redo the same check as before. At some point you'll get an error when you add a certain something, and you need to look for a solution from there.
Stupid, stupid me. I have used an sql-keyword (update) as a name for a member-variable of the class.
I assumed the ORA-01747 message wanted to tell me about a failing select, but instead a closer look revealed that it actually pointed out as to why the table was not created at all.
I use JPA 2 with Hibernate Entity Manager 3.6.4. Once I have marked my entities with various annotations (#Entity, #MappedSuperClass etc), I put in my persistence.xml file the default schema to use (hibernate.default_schema property).
I know it's possible to create automatically the objects contained in the schema.
But is it possible to create the schema itself automatically and then create the objects it contains ?
EDIT :
I use this parameter too : hibernate.hbm2ddl.auto, to tell Hibernate to create the schema if it doesn't exists yet. No luck, Hibernate doesn't create it !
I have googled a little bit and find this post : Hibernate hbm2ddl won't create schema before creating tables.
The fact that Hibernate does not create a schema before creating table is a bug. Other database suffer from this situation : H2, Postgresql etc.
This bug is planned to be fixed with 5.0.0 release of Hibernate.
So, for now, the only workaround is to create the schema by yourself, either manually or by a mean offered by your database vendor, since Hibernate can't do it itself :\
I managed to build a workaround that uses the hbm2ddl default flow.
Since it always calls the "database-object" drop statements BEFORE creating schema, you can do something like this:
<database-object>
<create></create>
<drop>DROP SCHEMA IF EXISTS myschema cascade; CREATE SCHEMA myschema</drop>
</database-object>
unfortunately the create clause is mandatory and sadly it's only executed AFTER schema creation, no matter what order you put it on cfg.xml, so I made it empty, that way you don't have errors trying to creating schema again (it was already created together with drop)