Hibernate - column name external configuration - java

We have a requirement where we need to have the column names externally configurable in Hibernate. The column names in the database will change in the future and we do not want to change the hibernate entity class (annotations) every time this happens.
What is the best approach for this scenario?

You cna either use a custom NamingStrategy (see here)
Or define dynamic maping (see here)

You can use hibernate mappings files
Check this link maybe it can help you
http://www.tutorialspoint.com/hibernate/hibernate_map_mapping.htm

You can keep column names in some class as constants, this way you would only need to update that class when column names change
public class MyEntityColumns {
public static final String COLUMN1 = "column1";
...
}
#Entity
public class MyEntity {
#Column(name = MyEntityColumns.COLUMN1)
private String someField;
}

Related

Spring JPA does not detect deleted tables

I deleted my tables to let them be recreated by Spring JPA, but spring does not create them. Instead, I'm getting the following exception:
Unable to create unique key constraint (guild_id, setting_key) on table guild_setting: database column 'guild_id' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
I don't know why I get this error, but before I deleted the tables in the database, the column name was guild_id, so what JPA says is not right.
This is an excerpt of the Entity:
#Entity
#Table(uniqueConstraints=#UniqueConstraint(columnNames={"guild_id", "setting_key"}))
public class GuildSetting extends Setting {
#Column(nullable = false)
private long guildId;
The following properties are set with the spring.datasource properties:
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
If you don't want to use #Column(name="guild_id")
You should use #UniqueConstraint(columnNames={"guildId", ...}
The generated table will contain the (correct) column, named guild_id
#Entity
#Table(uniqueConstraints=#UniqueConstraint(columnNames={"guildId", "setting_key"}))
public class GuildSetting extends Setting {
#Column(nullable = false)
private long guildId;
Agreed, this looks like a bug...
Note: You did not mention you have problems with the setting_key unique constraint.
Do you use #Column(name="setting_key") or private String setting_key?

Default naming policy for columns - is it possible? (JPA)

JPA newbie here. Here's my question:
Say we have an entity like this:
#Entity
#Table(name="thingies")
public class Thingy implements Serializable {
private Long thingyId;
private String thingyName;
private Integer thingyPrice;
// Constructor, getters, setters
}
Mapped to a table like this:
create table thingies (
thingy_id serial primary key,
thingy_name text,
thingy_price smallint
);
Is there a way to make the provider aware of the attribute naming policy instead of needing to explicitly provide a #Column annotation on each getter? In other words, can we automatically map all underscored names to the corresponding camelcased names without using #Column?
(I know I can quote names, that is not an answer to my question above.)
You need to add the following property to your persistence.xml file:
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
And all camelcasedproperty names will bemapped to underscored column names.
You should use #Column.
#Column(name="thingy_name")
private String thingyName;
Becouse 'thingy_name' is not equal 'thingyName'. JPA dont know what you want mapped. But in table thingyname and in entity thingyName is equal for JPA.
Use adnotation #Column, it does not take a lot of time. But you will get a explicit documentation.

Persisting third-party classes with no ID's

Say I have the following Java class, which is owned by a vendor so I can't change it:
public class Entry {
private String user;
private String city;
// ...
// About 10 other fields
// ...
// Getters, setters, etc.
}
I would like to persist it to a table, using JPA 2.0 (OpenJPA implementation). I cannot annotate this class (as it is not mine), so I'm using orm.xml to do that.
I'm creating a table containing a column per field, plus another column called ID. Then, I'm creating a sequence for it.
My question is: is it at all possible to tell JPA that the ID that I would like to use for this entity doesn't even exist as a member attribute in the Entry class? How do I go about creating a JPA entity that will allow me to persist instances of this class?
EDIT
I am aware of the strategy of extending the class and adding an ID property it. However, I'm looking for a solution that doesn't involve extending this class, because I need this solution to also be applicable for the case when it's not only one class that I have to persist, but a collection of interlinked classes - none of which has any ID property. In such a scenario, extending doesn't work out.
Eventually, I ended up doing the following:
public class EntryWrapper {
#Id
private long id;
#Embedded
private Entry entry;
}
So, I am indeed wrapping the entity but differently from the way that had been suggested. As the Entry class is vendor-provided, I did all its ORM work in an orm.xml file. When persisting, I persist EntryWrapper.
I don't have much experience with JPA, but I wouldn't extend your base classes, instead I would wrap them:
public class PersistMe<T> {
#Id
private long id;
private T objToWrap;
public(T objToWrap) {
this.objToWrap = objToWrap;
}
}
I can't test it, if it doesn't work let me know so I can delete the answer.

Bean validation Java conditional

Right now I have a class BaseSchedule It is used by 4 classes (composition). I would like to validate in two use classes and not in the others. I am a little stumped on how to do so.
My BaseSchedule looks like the following:
#Embeddable
#DatesStartBeforeEnd(start = "startDateTime", end = "endDateTime")
public class BaseSchedule implements Serializable {
private Date startDateTime;
private Date endDateTime;
}
I would like to check to make sure that the startDateTime and endDateTime are not null when I go to persist the data to my database. Normally I would provide a #NotNull to each of the fields.
public class TimeSlot implements Scheduleable {
#Embedded
private BaseSchedule schedule;
}
But... in the case of my TimeSlotTemplate I do not want validation as I know it will be null.
public class TimeSlotTemplate extends SchedulableClassTemplateEvent {
#Embedded
private BaseSchedule schedule;
}
If you're using Hibernate Validator as your BV provider, one solution might be to use a custom default group sequence provider.
For this to work, your BaseSchedule object would have to know about the "role" it currently has, e.g. by passing an enum with values such as SlotSchedule, TemplateSchedule etc. to its constructor. Depending on the role a group sequence provider could then determine the sequence to validate and return a sequence which does not contain the #NotNull constraints if the role is TemplateSchedule.
Not that this approach requires that you use the default sequence during JPA lifecycle validation.
I think this could be done using the #PrePersist Annotation.
#PrePersist
public void prePersist(){
if(isPerformNullableCheck()){
// check for null values and raise an error if invalid
}
}
in your TimeSlotTemplate, you can set the performNullableCheck property to false...
Another way might be to add a class into the hierarchy.
BaseSchedule contains the properties needed and e.g. ValidatedSchedule (extends BaseSchedule) overrides those and performs the notnull checks. Don't know whether this works or not. Also this would probably not be the best solution for your problem..?

Is it possible to map a field in an Entity without defining any association?

I've got the following schema in DB (simplified)
MainTable(
ID primary key
SOMEFIELD
CODE_FK1 -- references OtherTable1 CODE (without declared foreign key)
CODE_FK2 -- references OtherTable2 CODE (without declared foreign key)
... Other fields used
)
OtherTable1(
CODE primary key
LABEL
... other fields not used
)
OtherTable2(
CODE primary key
LABEL
... other fields not used
)
I'm asking if there is any way to define my Entity for main table in order to use directly labels from my other tables, i.e without defining entities for these other table.
I cannot change the DB schema, which is really awful (there are labels/code couples everywhere, defined in multiples tables).
And If it was possible, this solution would allow to keep my code simple, since I don't really need these other entities.
I guess it would result something like that:
#Entity
public class MainEntity{
#Id
private Integer ID;
#Column(name="SOMEFIELD")
private String SomeField;
#SomeAnnotation to Join CODE_FK_1 with OtherTable1.CODE
#SomeAnnotation like #Column(name="LABEL", table="OtherTable1")
private String Label1;
#SomeAnnotation to Join CODE_FK_1 with OtherTable1.CODE
#SomeAnnotation like #Column(name="LABEL", table="OtherTable1")
private String Label1;
}
Thanks by advance for your help!
Another possibility would be using the #Formula annotation to fetch the value from the other table. This will automatically generate a subselect whenever you load your Entity.
I think you'll need something like this:
#Entity
public class MainEntity{
#Id
private Integer ID;
#Column(name="SOMEFIELD")
private String SomeField;
#Formula("(SELECT ot1.LABEL FROM OtherTable1 ot1 WHERE ot1.CODE = CODE_FK_1)")
private String Label1;
}
There is little information about this in the [Hibernate docs][1], so you may need some trial and error to get it right (but you should be able to work it out with hibernate.show_sql=true.
There are 2 possible downsides to this approach:
This is hibernate-specific code
This is plain SQL, and may thus be database-specific
HTH
[1]: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-property hibernate docs
You can use the #SecondaryTable annotation. See this example:
https://github.com/hibernate/hibernate-orm/blob/823a5c1ede1869fd97471e3b8ebe7ec4ac8068e4/hibernate-core/src/test/java/org/hibernate/test/annotations/join/Dog.java#L20-L24

Categories

Resources