Is determinePrimaryKeyJoinColumnName() ever used in Hibernate 5 ImplicitNamingStrategy? - java

I am working on hibernate 5 and implemented the ImplicitNamingStrategy interface. Among other methods, there are two methods called determinePrimaryKeyJoinColumnName(...) and determineJoinColumnName(...). In the java doc, it says about determinePrimaryKeyJoinColumnName:
Determine the column name related to {#link javax.persistence.PrimaryKeyJoinColumn}. In
* {#code hbm.xml} terms, this would be a {#code } defined for a {#code }
* or a {#code } (others?)
I annotated my joins with PrimaryKeyJoinColumn and the code works, however the names never get routed through determinePrimaryKeyJoinColumnName(...) but through determineJoinColumnName(...).
Am I wrong in believing this is a bug?

#PrimaryKeyJoinColumn can be used like #JoinColumn only for the #OneToOne mapping. In such situation an additional join column is not used and, of course, the name of such "not existing column" is not generated.
#PrimaryKeyJoinColumn can be used for an inheritance too. For an example
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "someDiscriminator")
public class Customer {
#Id
#GeneratedValue
private Long customerPid;
#Column
private String customerName;
}
#Entity
#PrimaryKeyJoinColumn(name = "xxxYY")
public class ValuedCustomer extends Customer {
#Column
private String valuedCustomerName;
}
Hibernate will use xxxYY for a column name. But if you do not specify a name
#Entity
#PrimaryKeyJoinColumn
public class ValuedCustomer extends Customer {
#Column
private String valuedCustomerName;
}
}
Hibernate will not use determinePrimaryKeyJoinColumnName() to generate a name. So, looks like, it is a bug.
Hibernate calls determinePrimaryKeyJoinColumnName() only in one place Ejb3JoinColumn.java#L719. But I can't get in which situations this happens.
I have encountered such problems too, when try to implement an adapter of Hibernate 4 NamingStrategy for Hibernate 5. You can refer ImprovedNamingStrategy for Hibernate 5 for an additional notes.
And my try to implement Hibernate 5 Implicit Naming Strategy.

Related

Batch insert entity with composite key

Having these classes:
public class SomeCompositeKey implements Serializable {
private Long objectAId;
private Long objectBId;
private Long objectCId;
}
//lombok annotations~~
#Entity
#Table(name = "objects_assoc")
#IdClass(SomeCompositeKey.class)
public class ObjectsAssocEntity {
#Id
#ManyToOne
#JoinColumn(name = "object_a_id")
private ObjectAEntity objectA;
#Id
#ManyToOne
#JoinColumn(name = "object_b_id")
private ObjectBEntity objectB;
#Id
#ManyToOne
#JoinColumn(name = "object_c_id")
private ObjectCEntity objectC;
}
I'm fetching references of ObjectsAssocEntity members using EntityManager.getReference() and trying to save few entities at once using saveAll method, and each time hibernate executes select to check wheter entity exists or not and then make single insert in case when it not exists.
Is there any possibility to use batch insert in this case? Or should I try to do this e.g with native query?
As described in docs. The spring default implementation must know if the entity is new or not.
In the case of unique primary key: It's easier for spring determine if it's new because before insert the entity id is null.
In the case of a composite key: The ID values are always filled in before persist. So in this case, for determine if the entity is new or not, you can do one of the following approachs:
Use a #Version property in the entity class. For a new object, version is null. So that's enough.
Implement Persistable interface
Override the default spring SimpleJpaRepository EntityInformation and registering as a bean.
Suggestion: #Version has several benefits in the concurrency world. So use it.
Spring docs

Dynamic JPA #JoinColumn Name

I am not very experienced with JPA and was curious if the following is possible.
Say I have a class Project as follows:
#Entity
public class Project {
#Id
private String projectCode;
private String departmentId;
/*
* Is something like this possible with JPA?
*/
if (departmentId == null) {
#JoinColumn(name = "projectCode", referencedColumnName = "assignedProject")
} else {
#JoinColumn(name = "departmentId", referencedColumnName = "id")
}
#OneToMany(targetEntity = Employee.class)
private List<Employee> contributors;
// getters/setters
}
So I would like to populate the contributors list based on the presence of departmentId.
Is this possible with JPA? Or will I have to specify two List<Employee> fields, mapped by both variables, and preform proper checks within my application logic?
Thanks for your help.
/*
* Is something like this possible with JPA?
*/
if (departmentId == null) {
#JoinColumn(name = "projectCode", referencedColumnName = "assignedProject")
} else {
#JoinColumn(name = "departmentId", referencedColumnName = "id")
}
No, this isn't possible with JPA and you'll be glad that it isn't.
You can achieve what you want by using inheritance in Java. Begin by creating an abstract entity that contains all the common fields of your table. Then you can create an entity subclass with a projectCode attribute and another entity subclass with a departmentId attribute.
At the RDBMS level, for a simple object model like the one we just built, a single table can be mapped. In the abstract entity, you would annotate as follows to achieve this:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DTYPE", discriminatorType = STRING, length = 1)
#DiscriminatorValue("?")
#Entity
public abstract class Project {
:
:
}
#DiscriminatorValue("P")
public class ProjectCodeProject extends Project {
:
:
}
Remember that RDBMS has no knowledge or notion of inheritance. Inheritance exists only on the Java side. In the database, inheritance is represented by metadata. The "Discriminator" is a special column (here named "DTYPE") that appears in your database table that informs JPA which subclass a particular column represents. In the above, the code "P" was chosen to represent database records that have a PROJECTCODE attribute rather than a DEPARTMENTID attribute.
Using a class hierarchy like this would enable you to have a table whose rows can have either a departmentId or a projectCode as an attribute (not both). Because rows of the table are all Projects, developing common logic in Java to work with the subtypes ought to be relatively straightforward.

Cannot load entity by root class in joined inheritance chain with JPA (Hibernate)

I have the following inheritance chain:
#MappedSuperclass
public abstract class AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
Long id;
}
#Entity
#Table(name = "answers")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Answer extends AbstractEntity {
}
#Entity
#Table(name = "chosen_answers")
#PrimaryKeyJoinColumn
public class ChosenAnswer extends Answer {
#ManyToOne(optional = false)
#NotNull
AnswerChoice answerChoice;
}
#Entity
#Table(name = "free_text_answers")
#PrimaryKeyJoinColumn
public class FreeTextAnswer extends Answer {
String answerText;
}
The (simplified) sample content of my database looks like this:
answers:
--ID---
| 100 |
free_text_answers:
--ID----answer_text--
| 100 | "Some text" |
The foreignkey from free_text_answers(id) to answers(id) is created.
The problem is that the entity manager returns null for the following statement:
em.find(Answer.class, 100l); // returns null
although, 100 is a valid id for a stored answer. If I query the entity manager for instances of FreeTextAnswer, I get the expected result.
em.find(FreeTextAnswer.class, 100l) // returns stored entity
The strange thing is, as soon as I query the entity manager for the subtype, the first statement also returns the requested entity.
Is this the expected result? If yes, how do I design my inheritance chain to work the way I like?
I am using Spring Data Rest, and I only expose the Answer-entity via a RestRepository, therefore Spring Data Rest calls the entity manager with an Answer as the expected entity.
After some further debugging with the generated SQL statements, I found a workaround to solve the problem.
As you can see in the ER diagram below, one subclass of Answer has a OneToOne relationship to another entity. The default fetchtype for such a relationship is EAGER which turned out to be the problem.
As soon as I configured hibernate to lazy-load this relationship, everything works as expected.
Is this a bug in hibernate?

#embeddable vs #entity for a mapping a collection

This must be quite naive but I have a doubt on when to use #Entity and #Embeddable.
Say I have a User and Notification class.
#Entity
public class User{
//other properties
#onetomany
private List<Notification> notifications;
}
#Entity
public class Notification{
//properties
}
I understand that there will be tables for class User and Notification, and a third table for mapping.
What if I do it like this?
#Entity
public class User {
//other properties
#ElementCollection
private List<Notification> notifications;
}
#Embeddable
public class Notification{
//properties
}
I know this won't create a table for Notification. But I can still store my notification objects. I went through the documentation, but couple of doubts:
Is it based on whether I want to see class B as a seperate table?
Is there a performance difference b/w creating a table and an embeddable object?
What can I not do with embeddable object that I can do with a table other than directly querying the table?
NOTES
For anyone reading this question, this question too might help you.
Is it based on whether I want to see class B as a separate table?
Yes, when you use #Embedded, You embed that #Embeddable entity in #Entity class, which makes it to add columns for embedded entity in same table of #Entity class.
Is there a performance difference b/w creating a table and an embeddable object?
When you use #Embedded, for table creation, one query is required, also for inserting and selecting a row. But if you don't use it, multiple queries are required, hence, use of #Embedded yields more performance, we can say.
What can I not do with embeddable object that I can do with a table other than directly querying the table?
Removing the respective embedded entity may be, but there may be integrity constraint violations for this.
In JPA, there’s a couple ways to create composite key fields. Lets see the method using the #Embeddable annotation.
Let’s start with the Entity class.
#Entity
#Table
public class TraceRecord {
#Id
private TraceRecordPk id;
#Version
#Transient
private int version;
#Column(columnDefinition = "char")
private String durationOfCall;
#Column(columnDefinition = "char")
private String digitsDialed;
#Column(columnDefinition = "char")
private String prefixCalled;
#Column(columnDefinition = "char")
private String areaCodeCalled;
#Column(columnDefinition = "char")
private String numberCalled;
}
This is a pretty simple Entity class with an #Id and #Version field and a few #Column definitions. Without going into too much detail, you’ll see that the #Version field is also annotated #Transient. I’ve done this simply because my table also doesn’t have a column for tracking versions, but my database is journaled, so I’m not too concerned about versioning. You’ll also notice that the #Column fields have a value of “char” set on the columnDefinition attribute. This is because the fields in my table are defined as char and not varchar. If they were varchar, I wouldn’t need to do this since a String maps to a varchar field by default.
The #Id field is what I’m interested in right now. It’s not a standard Java type, but a class I’ve defined myself. Here is that class.
#Embeddable
public class TraceRecordPk implements Serializable {
private static final long serialVersionUID = 1L;
#Temporal(TemporalType.DATE)
#Column
private Date dateOfCall;
#Column(columnDefinition="char")
private String timeOfCall;
#Column(columnDefinition="char")
private String callingParty;
/**
* Constructor that takes values for all 3 members.
*
* #param dateOfCall Date the call was made
* #param timeOfCall Time the call was made
* #param callingParty Extension from which the call originated
*/
public TraceRecordPk(Date dateOfCall, String timeOfCall, String callingParty) {
this.dateOfCall = dateOfCall;
this.timeOfCall = timeOfCall;
this.callingParty = callingParty;
}
}
To make this class capable of being an #Id field on an Entity class, it needs to be annotated with #Embeddable like I mentioned earlier. The 3 fields I’ve selected for my composite key are just normal #Column definitions. Rather than create getters/setters for each field, I’ve simply implemented a constructor that takes values for all 3 fields, making any instance immutable. When annotating a class with #Embeddable, that class will need to implement Serializable. So I’ve added a default serialVersionUID to accomodate.
Now that you have a class created and annotated with #Embeddable, you can now use it as the type for an #Id field in your Entity class. Simple stuff eh.

NullPointerException at org.hibernate.envers.event.AuditEventListener.generateBidirectionalCollectionChangeWorkUnits(...)

I'm using Envers to audit different fields of my entities. The framework works in general but it seems to have problems with some kinds of entity mapping. All former problems I could solve myself... but this time I'm stuck.
When inserting some entity into the database I get the following exception:
Caused by: java.lang.NullPointerException
at org.hibernate.envers.event.AuditEventListener.generateBidirectionalCollectionChangeWorkUnits(AuditEventListener.java:108)
I'm not completly sure which entity causes this because it is fired during flush() and the complex application inserts many different entities within one larger transaction.
We are using some HibernateEventListener that fires right before that exception... so I suppose that entity is the cause. The persistence.xml is configured this way:
<property name="hibernate.ejb.event.post-insert" value="com.xyz.hibernate.events.listeners.MyListener,org.hibernate.envers.event.AuditEventListener" />
If this is true than the entity is the following (excerpt):
#Entity
#Table(name = Property.TABLE_NAME, uniqueConstraints = #UniqueConstraint(columnNames = { "ENTITY_ID", "DESCRIPTOR_ID", "PROMOLEVEL_ID" }))
public class Property extends AbstractEntity {
private static final long serialVersionUID = 1L;
public static final String TABLE_NAME = "E_BUSINESS_PROPERTIES";
public static final String PROPERTY_ENTITY = "entity";
public static final String PROPERTY_DESCRIPTOR = "descriptor";
public static final String PROPERTY_PROMOLEVEL = "promolevel";
#Audited
#ManyToOne(optional = false)
private ProjectPropertyDescriptor descriptor;
#Audited
#ManyToOne
private ExtendedEntity entity;
#Audited
#ManyToOne
private AbstractPromotionLevel promolevel;
#Audited
#OneToMany(cascade = { CascadeType.ALL }, mappedBy = PropertyValue.PROPERTY_PROPERTY)
private List<PropertyValue> propertyValues = new ArrayList<PropertyValue>();
// some accessors stripped!
}
Does anyone have an idea where to look for? As soon as we disable Envers everything works fine. But we need envers to generate a history of changes.
I found the solution of my problem. So I'll share it for others.
The reference to the ExtendedEntity caused the problem. ExtendedEntity is an audited class with different subclasses. But Envers does not automatically mark the subclass as audited. The subclass must use the #Audited annotation for the class or any own fields to be audited by Envers.
So a reference to any sublass of ExtendedEntity, that was audited, worked. In my case I've referenced another subclass that was not audited by Envers - and so the NullPointerException was thrown. By simply adding the #Audited annotation to that empty extension of the ExtendedEntity class (no own properties... just a subclass to distinguish another type of entity) and creation of the related versioning table in the database I could close that gap and solve my problem.
Remember to mark subclasses with #Audited at any own field or the class itself - otherwise they aren't audited and you might come across the exact same problem.

Categories

Resources