How to customize hibernate #ElementCollection envers audit table name? - java

I'm currently using Hibernate & Envers version 5.2.9.Final. I want to use #ElementCollection with a custom table name for both the collection and the audit table.
What I know so far is that modifying default table names has a variety of annotations to work with: For the entity itself there are the annotations #Table and #SecondaryTable as well as the corresponding envers annotations #AuditTable and #SecondaryAuditTable. For changing the table name of an element collection there is the #CollectionTable annotaion. I have not been able to find a corresponding envers annotation so far. So my question is:
How can I change the name for a hibernate #ElementCollection envers audit table?
Additional info
In the hibernate envers ticket which tracks the adding of auditing support for element collections, the same question was asked back in 2013 but not answered.
A code snippet to make my setup clear:
#Entity
#Table(name = "\"user\"")
#SecondaryTable(name = "\"user_secondary\"")
#Audited
#AuditTable("\"user_audit\"")
#SecondaryAuditTable(secondaryTableName = "user_secondary",
secondaryAuditTableName = "\"user_secondary_audit\"")
public class User {
// ... stuff like id and other fields ...
#ElementCollection
#CollectionTable(name = "\"user_references\"")
private Map<String, Long> references = new HashMap<>();
// TODO FIXME how to get a custom name for the audit table?
// ... more stuff like getters and setters
}
Hibernate generates all tables as intended, yet the collecction audit table is named 'user_references_AUD' while I would like to get the name 'user_references_audit' like for the other tables.
I'm also aware of the global settings affecting the audit table prefix or suffix, but that is only a last resort for my use case.
Update
As suggested I added a feature request to Hibernate JIRA.

That is because Envers has no complement for #CollectionTable.
You are welcomed to add a JIRA requesting that we add a complementing annotation and I can look at what is needed to add the functionality. Just at a glance, it shouldn't require too much as it merely needs to feed into the generated Envers entity table name for the collection middle entity.

Related

Hibernate Envers can't resolve audit table

I have a JPA entity which I want audited. I added Envers to my project, and added the #Audited annotation to the entities I need. Now, the changes are being logged in the audit tables, but I cannot retrieve them through the audit readers provided by Envers.
My entity is as follows.
#Entity
#Audited
#AuditTable(value = "blog_posts_AUD")
#Table(name = "blog_posts")
public class Post {
...
}
I'm trying to query the audit tables as follows.
AuditReader reader = AuditReaderFactory.get(entityManager);
List revisions = reader.getRevisions(Post.class, primaryKey);
This fails, because the SQL call contains a reference to a table called org.foo.bar.blog_posts_AUD, which obviously does not exist. It seems that Hibernate is not picking up the #AuditTable annotation (or the default audit table suffix, for that matter). Anyone ever faced this before?

Fetch ManytoOne based on certain condition

I am using Hibernate 3.5.4 version as Orm I have two tables which have many to one relationship , Like Table 'Book' can have many 'Authors' associated with It.
#OneToMany(mappedBy = "key.bookId", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Set<BookAuthor> getAuthors() {
return authors;
}
But we use soft delete for deleting the association (we maintain a column named isDeleted) , i want to fetch the entity based on isDeleted check if its 1 it should not be loaded , else if 0 load it.
Is it possible by modifying this current fetching strategy to provide above support or there is another better solution that can be applied please let me know.
Have a look at the #Filter or #Where Annotation.
As far as I know this is the usual way to restrict collection fetching.

Mapping one DB column to two seperate fields using JPA

I'm developing a code generator that have to generate JPA entities from database meta-model files. These model are from home-brewed modeling system which are being used to generate models other than JPA entities.
In these models some fields are mapping back to same database column. But it seems like JPA does not like that very much. When I try to run generated code I get
Exception [EclipseLink-48] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [FACT_INVENT_TRANS_HIST_DM.TRANSACTION_ID]. Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[TransactionIdKey-->FACT_INVENT_TRANS_HIST_DM.TRANSACTION_ID]
Descriptor: RelationalDescriptor(InventTransHistFactDM --> [DatabaseTable(FACT_INVENT_TRANS_HIST_DM)])
As I can't change the models only option left is to make one of those fields read-only. And the JPA entities being generated are only used to read data from database it will not used for writing data. Is there a way to mark some fields as read only or tell EclipseLink that these entities are read only so it does not have to worry about the multiple writable mapping.
I tried using EclipseLink's #ReadOnly annotation in all entities but it did not help this issue.
There is no #ReadOnly in JPA.
There are however attributes "insertable"/"updatable" that you can set against a field via #Column to effectively do the same.
The question may be almost 6 years old, but it's still being found today, so I'd like to address another option:
public class Foobar {
#OneToOne
#JoinColumn(name="SELF_COLUMN_FOO", referencedColumnName = "FOREIGN_COLUMN_TO_JOIN")
public Foo foo;
#OneToOne
#JoinColumn(name="SELF_COLUMN_BAR", referencedColumnName = "FOREIGN_COLUMN_TO_JOIN")
public Bar bar;
}
This can be used where SELF_COLUMN is obviously the relevant column in the Foobar table, and FOREIGN_COLUMN_TO_JOIN would be single key in the other table you wish to join.
This will be useful where you want to have two (or more) attributes in a single class, but only one column to join on the foreign DB table. For example: An Employee may have a home phone number, cell number, and a work phone number. All are mapped to different attributes in the class, but on the database there's a single table of phone numbers and id's, and an identifier column, say VARCHAR(1) with 'H' or 'W' or 'C'. The real example would then be...
Tables:
PHONENUMBERS
PHONENUMBER_ID,
ACTUAL_NUMBER
EMPLOYEE
ID
HOMENUMBER VARCHAR(12),
CELLNUMBER VARCHAR(12),
WORKNUMBER VARCHAR(12)
public class Employee {
#OneToOne
#JoinColumn(name="HOMENUMBER", referencedColumnName = "PHONENUMBER_ID")
public Phone homeNum;
#OneToOne
#JoinColumn(name="CELLNUMBER", referencedColumnName = "PHONENUMBER_ID")
public Phone cellNum;
#OneToOne
#JoinColumn(name="WORKNUMBER", referencedColumnName = "PHONENUMBER_ID")
public Phone workNum;
}
As you can see, this would require multiple columns on the Entity's table, but allows you to reference a foreign key multiple times without throwing the 'Multiple writable mappings exist...' that you showed above. Not a perfect solve, but helpful for those encountering the same problem.

redundant id values inserted despite using #inheritance

In a spring mvc app using hibernate, jpa, and MySQL, I have a BaseEntity that contains an id field that is unique across all classes that inherit from BaseEntity, using #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS). Some data is imported into the MySQL database using an external dml.sql file run from the command line. The imported data is carefully planned so that all the ids that need to be managed as part of the BaseEntity inheritance group are unique within their inheritance group.
The problem is that hibernate is not taking the values of the ids already in the database into account when it inserts a new record into the database. Instead, hibernate is saving an id value in one of the descendent entities which is identical to an id stored in one of the other descendent entities.
How can I configure hibernate to respect the id values already in the database when it saves a new entity within the same inheritance group?
Some relevant facts are:
All of the objects in the MySQL database were created directly from the hibernate mappings in the app by using hbm2ddl.
I cannot use #MappedSuperClass for BaseEntity because BaseEntity is used as a property of one of the entities in the app, so that entities of various types can be stored in the same property of that entity. When I was using #MappedSuperClass, eclipse was giving compile errors saying that BaseEntity cannot be instantiated directly because it has #MappedSuperClass annotation.
Note: The file sharing site seems to be center-justifying all the code. You can fix this by simply cutting and pasting it into a text editor.
You can read the code for BaseEntity by clicking on this link.
The code for the entity whose id values are being set incorrectly by hibernate can be read by clicking on this link.
The jpql code for saving the entity whose id is being set incorrectly is as follows:
#Override
#Transactional
public void saveCCD(HL7ConsolidatedCareDocument ccd) {
if (ccd.getId() == null) {
this.em.persist(ccd);
this.em.flush();
}
else {
this.em.merge(ccd);
this.em.flush();
}
}
I have never done this using hibernate or mysql ut have done something similar with EclipseLink + PostgreSQL. So there might be some mistakes below.
With generation type TABLE you might want to explicitly specify some additional parameters using the TableGenerator annotation. That way you are certain where hibernate is storing things.
#Id
#GeneratedValue(
strategy=GenerationType.TABLE,
generator="TBL_GEN")
#javax.persistence.TableGenerator(
name="TBL_GEN",
table="GENERATOR_TABLE",
pkColumnName = "mykey",
valueColumnName = "hi"
pkColumnValue="BaseEntity_Id",
allocationSize=20
)
What you need to do when you bypass hibernate is to reserve the ids you need by updating the row with mykey BaseEntity_Id in the table GENERATOR_TABLE.
For details on the annotations see paragraph 5.1.2.2

JDO - 1-N unidirectional relation using annotations - Column name?

I'm using JDO (with Datanucleus implementation) for a new project for the first time, and I'm having troubles defining 1-N unidirectional owned relation using JDO annotations. What I need is to have a collection of Subitems in an Item, such that a Subitem doesn't have a reference to the owner:
#PersistenceCapable(detachable = "true")
public class Item {
...
#Persistent(defaultFetchGroup = "true")
Collection<Subitem> subitems;
...
}
It's all well and good, but how can I define which existing RDBMS column the relation maps to? AFAIK an owned 1-N is realized in a DB by creating a non-nullable table column in a child table but I don't have (and don't want) a parent reference class field in a Subitem which I can then decorate with #Column(name="...") annotation.
And how to properly use #ForeignKey annotation in JDO3? The annotation accepts the name of the FK constraint but not the corresponding FK table and column specification. By definition a FK is a ref. constraint between two tables based on a common key, but I can't seem to specify the other table and a common key(#ForeginKey at Datanucleus JDO docs ).
Edit:
#Element(column="...") annotation should be used instead:
#PersistenceCapable(detachable = "true")
public class Item {
...
#Persistent(defaultFetchGroup = "true")
#Element(column="itemId")
Collection<Subitem> subitems;
...
}
As it's clearly stated in the documentation links in the answer.
JDO (or JPA too for that matter) doesn't have "owned" relations, just relations (it is a term I've only ever heard of in relation to GAE's datastore, and you're not using that).
DataNucleus docs defines all such relations adequately IMHO so just navigate the menu from where you got to, for example
http://www.datanucleus.org/products/accessplatform_3_1/jdo/orm/one_to_many_collection.html#fk_uni
http://www.datanucleus.org/products/accessplatform_3_1/jdo/orm/constraints.html#fk

Categories

Resources