#Audited table and byte[] #Lob field problem - postgresql

I have adudited table with #Lob field. Without #Audited saving object by Spring CrudRepository works ok, but when i want audit turn on i get error: PSQLException: ERROR: column "content" is of type oid but expression is of type bytea. How to resolve this ? Content column in PostgreSQL database is oid type (for both tables). On Hibernate 5.x the same configuration works, but not o Hibernate 6.x.
#Entity
#Audited
#Table(name = "up_test")
#Getter #Setter
public class UploadTestEntity extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "up_test_seq")
#TableGenerator(table = "id_generator", name = "up_test_seq", initialValue = 1, allocationSize = 1)
private Integer id;
#Lob
private byte[] content;
}

Just remove the #Lob annotation.
The Postgres JDBC driver does not support handling the bytea type via the JDBC LOB APIs setBlob()/getBlob(). I don't know why, and it seems like something that should be supported.
But on the other hand, you don't need it here. The most natural way to handle a field of type byte[] mapping to bytea is to use setBytes()/getBytes(), which is the job of Hibernate's VarbinaryJdbcType.
I don't know where people got the idea that they needed to use #Lob for this instead of just going with the default mapping for byte[].

Related

read columns with psql client, which were written with JPA AttributeConverter

I have a psql table were a column written by JPA AttributeConverter
https://docs.oracle.com/javaee/7/api/javax/persistence/AttributeConverter.html
public class MyEntity {
#Id
#GeneratedValue
private UUID id;
#Lob
#Convert(converter = MyAttributeConverter.class)
private Object value;
The type of the column seems to be oid.
The converter simply seems to turn Object to a byte[]
How can I read the content of column value in a psql command line client?
Can I somehow bind the converter Java class?
Can I use decode?

Hibernate Search and composed key using #IdClass

I have a problem to integrate Hibernate Search in existing project with hundreds of entities but at least half of entities use #IdClass annotation as composed key. Can I solve the problem using the annotation #IdClass?
I also read this post Hibernate search and composed keybut I have not managed to solve my problem.
I have the following example:
entity class:
#Entity
#Table(name="FAKVS_DB")
#IdClass(value=PK_FAKVS_DB.class)
#Audited
#Indexed
public class FAKVS_DB implements Serializable {
#Id
#Column(name="Key_FAM", length=10, nullable=false)l
private String keyFam;
#Id
#Column(name="Komponentennr", nullable=false)
private Integer komponentenNr;
#Id
#Column(name="Hinweis", nullable=true, length=4)
private String hinweis;
//getters and setters
}
and composed key:
public class PK_FAKVS_DB implements Serializable {
private String keyFam;
private Integer komponentenNr;
private String hinweis;
//getters and setters
}
The error that occurs is:
HSEARCH000058: HSEARCH000212: An exception occurred while the MassIndexer was transforming identifiers to Lucene Documents
java.lang.ClassCastException: package.entities.module.fi.pk.PK_FAKVS_DB cannot be cast to java.lang.Integer
at org.hibernate.type.descriptor.java.IntegerTypeDescriptor.unwrap(IntegerTypeDescriptor.java:36)
at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:63)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:90)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:286)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:281)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1995)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1966)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1901)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1862)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1839)
at org.hibernate.loader.Loader.doQuery(Loader.java:910)
If I can not use #IdClass annotation can you tell me what are the alternatives?
Thank you very much in advance.
An alternative is to add a new property to be used as Id by Hibernate Search. You can mark this with #DocumentId to have the Hibernate Search engine treat the alternative property as the identifier in the index.
You will need to ensure that this new property is unique of course; this can typically done by generating a String from the real id. You probably want to annotate the new getter with #Transient so that it doesn't get persisted in the database.

JPA: Usage of #GeneratedValue on non-id column

I am attempting to persist an entity with an attribute that I want to be populated from a DB sequence. I'm using Oracle, have created the sequence, verified the sequence works via sql, and yet my attribute isn't getting populated. Here's what I have:
#GeneratedValue(generator = "RFQ_LINE_IDS_SEQUENCE", strategy=GenerationType.SEQUENCE)
#SequenceGenerator(name="RFQ_LINE_IDS_SEQUENCE", sequenceName="RFQ_LINE_IDS_SEQUENCE", allocationSize=1000000000)
#Column(name = "external_line_item_id")
private String externalLineItemId;
All the examples I'm seen online show this annotation being used with #Id, but I have another attribute that I'm using for my id.
I've also tried the following to no avail:
#GeneratedValue(generator = "RFQ_LINE_IDS_SEQUENCE", strategy=GenerationType.SEQUENCE)
#GenericGenerator(name = "RFQ_LINE_IDS_SEQUENCE", strategy = "sequence",
parameters = {#Parameter(name = "sequence", value = "RFQ_LINE_IDS_SEQUENCE")})
#Column(name = "external_line_item_id")
private String externalLineItemId;
JPA only mandates support for #GeneratedValue on #Id fields. Some JPA implementations (such as DataNucleus JPA) support it but not all do.
I have created a proposal for JPA to support #GeneratedValue for non-id attributes. Please vote here for this to be included in 2.2
https://java.net/jira/browse/JPA_SPEC-113

Merging an object with FetchType.EAGER relation leads to "FailedObject"

I have an entity VM with a relationship to another entity BP. The relationship is eagerly fetched. First I load a VM. After loading the VM is detached, serialized and changed at the client side. Now I want to update the changed entity so I use the EntityManager.merge() method from JPA. Now I run into the following error from OpenJPA:
"Encountered new object in persistent field "Vm.bp" during attach. However, this field does not allow cascade attach. Set the cascade attribute for this field to CascadeType.MERGE or CascadeType.ALL (JPA annotations) or "merge" or "all" (JPA orm.xml). You cannot attach a reference to a new object without cascading."
Why do I have to add a Cascade.MERGE to a relationship to another entity that will never change? And why does JPA think that BP is a new object ("...cannot attach reference to a new object...")?
When using ManyToOne relationships do I always have to add Cascade.MERGE in order to update the entity or is this because of the EAGER fetch type?
Here's my entity:
#Entity
#Table(name = "VM")
public class Vm extends BaseEntity implements Serializable {
public static final long serialVersionUID = -8495541781540291902L;
#Id
#SequenceGenerator(name = "SeqVm", sequenceName = "SEQ_VM")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SeqVm")
#Column(name = "ID")
private Long id;
// lots of other fields and relations
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "BP_ID")
private Bp bp;
// ...
}
I found the reason why this error message comes up: The #Version annotated database field of the related Bp entity was initialized with "0". Apparently OpenJPA (1.2.3) is not able to cope with entity versions of zero.
Setting the version to 1 solved my issue.

Why is this JPA 2.0 mapping giving me an error in Eclipse/JBoss Tools?

I have the following situation:
(source: kawoolutions.com)
JPA 2.0 mappings (It might probably suffice to consider only the Zip and ZipId classes as this is where the error seems to come from):
#Entity
#Table(name = "GeoAreas")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)
public abstract class GeoArea implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
protected Integer id;
#Column(name = "name")
protected String name;
...
}
#Entity
#Table(name = "Countries")
#DiscriminatorValue(value = "country")
public class Country extends GeoArea
{
#Column(name = "iso_code")
private String isoCode;
#Column(name = "iso_nbr")
private String isoNbr;
#Column(name = "dial_code")
private Integer dialCode = null;
...
}
#Entity
#Table(name = "Zips")
#IdClass(value = ZipId.class)
public class Zip implements Serializable
{
#Id
#Column(name = "code")
private String code;
#Id
#ManyToOne
#JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null;
...
}
public class ZipId implements Serializable
{
private String country;
private String code;
...
}
Pretty simple design:
A country is a geo area and inherits the ID from the root class. A ZIP code is unique within its country so it combines an ISO code plus the actual ZIP code as PK. Thus Zips references Countries.iso_code, which has an alternative unique, not-null key on it (reference to non-primary key column!). The Zip.country association gets an #Id annotation and its variable name is the same as the one in its ID class ZipId.
However I get this error message from within Eclipse (also using JBoss Tools):
Validation Message:
"The attribute matching the ID class attribute country does not have the correct type java.lang.String"
Why is this wrong in JPA 2.0 syntax (see #Id annotation on Zip.country)? I don't think it is. After all the types of Zip.country and ZipId.country can't be the same for JPA 2 because of the #Id annotation on the #ManyToOne and the PK being a simple integer, which becomes the ID class counterpart. Can anyone check/confirm this please?
Could this be a bug, probably in JBoss Tools? (Which software component is reporting the above bug? When putting the 3 tables and entity classes into a new JavaSE project there's no error shown with the exact code...)
Answering own question...
The way I modeled the reference, I use a String because the FK points to the iso_code column in the Countries table which is a CHAR(2), so basically my mapping is right. However, the problem is that JPA 2.0 doesn't allow anything but references to primary key columns. This is what the Eclipse Dali JPA validator shows.
Taken from "Pro JPA 2.0" by Keith/Schincariol p.283 top, "Basic Rules for Derived Identifiers" (rule #6): "If an id attribute in an entity is a relationship, then the type of the matching attribute in the id class is of the same type as the primary key type of the target entity in the relationship (whether the primary key type is a simple type, an id class, or an embedded id class)."
Personal addendum:
I disagree with JPA 2.0 having this limitation. JPA 1.0 mappings allow references to non-PK columns. Note, that using JPA 1.0 mappings instead isn't what I'm looking for. I'd rather be interested in the reason why this restriction was imposed on JPA 2.0. The JPA 2.0 is definitely limiting.
I'd say focus your attention on the CompoundIdentity relationship. See this question, and my answer there
Help Mapping a Composite Foreign Key in JPA 2.0
ZipId has no "country" field in your case
I have not tested your code, but it looks pretty much related to the use of the #PrimareKeyJoinColumn annotation.
The JPA 2.0 specification in section 11.1.40 states:
The PrimaryKeyJoinColumn annotation is
used to join the primary table of an
entity subclass in the JOINED mapping
strategy to the primary table of its
superclass; it is used within a
SecondaryTable annotation to join a
secondary table to a primary table;
and it may be used in a OneToOne
mapping in which the primary key of
the referencing entity is used as a
foreign key to the referenced
entity[108].
The example in the spec looks like your case.
#Entity
#Table(name="CUST")
#Inheritance(strategy=JOINED)
#DiscriminatorValue("CUST")
public class Customer { ... }
#Entity
#Table(name="VCUST")
#DiscriminatorValue("VCUST")
#PrimaryKeyJoinColumn(name="CUST_ID")
public class ValuedCustomer extends Customer { ... }
I hope that helps!