Changing naming strategy of #Table and #Column with EclipseLink to lower-case - java

When defining a JPA Entity like this:
#Entity
#Table
public class CaseExample implements Serializable {
#Id
Long id;
#Basic
String fooBar;
}
the automatically created SQL table name is "CASEEXAMPLE" and the column name "FOOBAR".
How can I change that from upper-case to lower-case-with-underscore e.g. "case_example" and "foo_bar" without having to add a name="foo_bar" to every single #Table and #Column?
Is the naming strategy defined by JPA or implemenation dependend? I use JPA 2.0 with EclipseLink 2.5.0.

JPA standardizes the names. I would leave them using the standard, or use #Column to change specific ones.
With EclipseLink you could modify you column names using your own code in a DescriptorCustomizer or SessionCustomizer. You would just iterate over your descriptor's mapping and reset the fieldNames based on your naming convention.

Related

when is a #Column annotation required for persistent properties of JPA classes?

In my JPA model I typically annotate each persistent class with #Entity and each persistent property with an appropriate annotation e.g. #Id, #Column, #ManyToOne, etc. A typical example is
#Entity
#Table(name = "files")
public class StoredFile {
#Id
#Type(type = "uuid-char")
private UUID id;
#Column(name = "file_name")
private String fileName;
// getters and setters omitted
}
I was looking at this example entity class and noticed that only the id field has a JPA annotation, i.e. there are no annotations specified for name or price.
Under what circumstances will a property of an #Entity be persisted if there are no annotations on the field/getter/setter?
You don't need to specify #Column annotation to persist a bean property.
#Column has to be used to specify a name of a table column. So if a naming strategy is used, you don't need to use #Column.
My advice is to always use #Column even if you don't need to specify a name.
#Column
private String fileName;
Also never mix fields and getters annotations.
Everything is primary for Hibernate.

Can I use Java 16 record with JPA entity?

I am trying to do something similar like below.
#Entity
#Table(name="Sample")
public record Sample(Integer id, String name) {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="user_id")
private Integer id;
#Column(name="username")
private String name;
}
However, it gives me error "User declared non-static fields id are not permitted in a record"
and same for name field as well.
Is there a way to use new java feature "record" with JPA annotation?
See the article, Using Records as Projections in JPA by Billy Korando. The following is a brief summary.
Records cannot be Entities
Jakarta Persistence (JPA; formerly Java Persistence API) implementations such as Hibernate depend on features either forbidden or not recommended by the JEP 395: Records spec: no-arg constructors, non-final fields, setters, etc.
➥ So, no, records cannot be used as JPA Entity.
Other uses of records
You can use records with:
CriteriaBuilder
TypedQuery
NativeQuery
Mapping definition
Spring data has some support as well.
See that article linked above for details, and for links to two other articles.

JPA-annotated POJOs are not mapped correctly when #Column is not used for all members

I have a custom POJO on which I am mapping the database records using JOOQ .fetchInto(TestClassDto.class). Most of the fields in my POJO are exactly similar to a database table's columns. However, there are a few that are different, therefore, I added java persistence and used #Column to explicitly map such columns on my POJO as described here.
Unfortunately, this is not working if I use #Column on a few specific fields. Only the fields that are annotated with #Column are mapped and the rest are ignored and set Null even though they are similar to the table column name and should be mapped implicitly.
Could you give me a hint if I am missing anything?
Sample POJO:
#Getter
#Setter
public class TestClassDto {
#Column(name = "field_AB_XYZ") // explicit mapping is required, thus need #Column
private Long myfieldAB;
/* Here, mapping could be implicitly done without using #Column because
** database column name and POJO property is same but it stays empty if I
** ignore #Column */
#Column(name = "hello_world")
private Long helloWorld;
}
Lastly, If I completely remove #Column from POJO's properties, helloWorld property is filled (implicitly) but myfieldAb remains NULL (because mapping is not found as expected).
Below is sample query:
dslContext.select()
.from(SOMETHING)
.where(SOMETHING.NAME.eq("Something"))
.fetchInto(TestClassDto.class)
As of jOOQ 3.15, you either have to annotate
all of your attributes...
none of your attributes...
... with the #Column annotation. There's a pending feature request to mimick JPA more closely and make the #Column annotation optional for some attributes: https://github.com/jOOQ/jOOQ/issues/4586.
In the meantime, instead of using those JPA annotations, you could add auxiliary getters/setters for your column:
public void setFieldAbXyz(Long v) {
this.myfieldAB = v;
}
public Long getFieldAbXyz() {
return myfieldAB;
}

How to force Eclipse Link creates Tables exactly same ClassName?

I'd like JPA EclipseLink creates tables exactly as is the ClassName (and fields) WITHOUT annotation #Table and #Column. It's always creates tables and fields with UPPERCASE, which makes readability difficult in the DB console.
ex.:
#Entity
public class ChannelEntity {
#Id #GeneratedValue
public Long id;
public String name;
public String description;
public Boolean oficial;
#Temporal(TemporalType.TIMESTAMP)
public Date creation;
}
And I'd like results in
Table: ChannelEntity
id creation description name oficial
----------------------------------------------------
351 NULL meu desc meu nome 1
Maybe exist same parameter in persistence.xml, but I can't find it.
If EclipseLink behaves correctly, the parameter you are looking for is delimited-identifers. From the JPA 2.1 spec:
It is possible to specify that all database identifiers in use for a
persistence unit be treated as delimited identifiers by specifying the
<delimited-identifiers/> element within the persistence-unit-defaults
element of the object/relational xml mapping file. If the
<delimited-identifiers/> element is specified, it cannot be
overridden.
If this element is included, EclipseLink should delimit all database identifiers in its generated SQL, which would cause the database objects to be created with case-sensitive names.

Over ride default fetch to skip rows with certain values

I am using Java, Hibernate, Spring Data and fairly new to this technology. I need to figure out how to Skip rows that are marked as 'archived.' We have a strict guidance from our DB architect that no rows shall be deleted from the database.
#MappedSuperclass
public class AbstractEntity implements Identifiable<String> {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy="uuid")
private String id;
private boolean archived; //<----?
}
#Entity
public class Employee extends AbstractEntity {
private String title;
private String fullName;
#ManyToOne
private Department dept;
}
#Entity
public class Department extends AbstractEntity {
private String name;
}
In the above example, any class extending AbstractEntity should never return rows that have archived == true. All my domain classes will be extending AbstractEntity so I'd like a solution that's either implemented in AbstractEntity.java or at some global configuration so that all generated SQL calls are 'where [table].archived <> true'
Take a look at Hibernate Filters.
#FilterDef(name="activeOnly")
#Filter(name="activeOnly", condition= "archived <> 1")
// assumes that all tables have a numeric column "archived"
// as you can notice, this is a filter at the SQL Level
// (not at the Entity level)
#MappedSuperclass
public class AbstractEntity // ....
I've never used Spring Data, but the Adding custom behavior to all repositories section of the official documentation lead me to belieave that it is quite easy to obtain an injected EntityManager and customize its behaviour. Just unwrap it and enable the filter.
Session session = entityManager.unwrap(Session.class);
session.enableFilter("activeOnly");
If you want the filter to be applied for all subclasses of the #MappedSuperclass use a recent version of Hibernate. Only version 3.5 and greater (see HHH-4332) supports this behaviour.
Also, there is one gotcha, you may need to repeat the filter on associations (See Hibernate Filters on related table with MappedSuperClass).
If you want to customize the delete operations as well, use #SQLDelete to mark archived = 1 (see Soft deletes using Hibernate annotations). But to the best of my knowledge this only works on mapped entities (nothing can be done at the #MappedSuperclass level)

Categories

Resources