Hibernate Many-To-One using other schema on DB2 - java

I am using hibernate-annotation (entitymanager) to handle my db2 databases using separate schema.
My main schema is called "mainschema". It has a table for fileuploads.
Then I have some other schema (schema1, schema2, schema3, schemaN).
How can I tell the many-to-one relationship on the schemaN to refer to the filetable on "mainschema". If I open the connection, I tell which schema to use. But the many-to-one is still using that schema and the fileupload table is only available in the "mainschema"
Thanks for help!
EDIT:
My fileupload hibernate bean using explicit the main schema:
#Entity
#Table(name="DOKUMENT", schema="mainschema")
Then I have one schema for every client, have a look at here:
The Schema is not set in the bean. It is set instead in time where the connection is opened.
#Entity
#Table(name="SOMETABLE")
This table "SOMETABLE" is existing in every schema for every client.
It refers to the dokument entity with an many-to-one
#Many-To-One
#JoinColumn(name="DOKUMENT_ID")
public Dokument getDokument() { return dokument }
public void setDokument() { this.dokument = dokument }
Question can be closed. It is working without any changes, because hibernate is still using "mainschema" automaticly.

This is how to map SchemaN to MainSchema one-to-many
#Entity
public class SchemaN{
#OneToMany(targetEntity=MainSchema.class, mappedBy="pk_SchemaN")
private List<MainSchema> ms;
...
}
#Entity
public class MainSchema{
#ManyToOne
#JoinColumn(name="FK_MainSchema")
private SchemaN pk_schemaN;
...
}
Hope this helps you it should be the same for any Schema1 to N

Related

Can I create a entity mapping to table which has a name from specific property of the entity?

For example, I have an entity below.
#Entity
public class Indexer
#NotNull #Id
private long id;
#Column
private string volumeKey;
}
I want to create a table with a ‘volumeKey’ property in this entity.
For example, A indexer has a ‘X12372’ as a volumeKey of property. I want this entity to be mapped to ‘INDEXER_X12372’.
And I tried to create custom NamingStrategy class for Indexer. And I can’t get an entity to be mapped in this class for making a table of name from.
You want the table to be used to be determined by a value of a property.
This is not possible with JPA or Spring Data JPA.
But some (many?) databases can do this transparently with partitioned tables.
See https://docs.oracle.com/cd/B28359_01/server.111/b32024/partition.htm for Oracle documentation as an example.
It should be easy enough to find a similar document for the database you use.

How to set the schema of #OneToMany autogenerated tables?

I want to put all of the following autogenerated tables into a specific schema.
#Entity
#Table(name = "master_table", schema = "test")
public class MasterTable {
#OneToMany
private List<VideoEntity> videos;
#Entity
#Table(name = "video_entity", schema = "test")
public static class VideoEntity {
}
}
Result: there are the two entity tables in test schema, but also one in the public schema called master_table_videos for the list mapping.
Question: how can I tell hibernate to also put the list-mapping table in the same schema than the others?
I think you should use the #JoinTable annotation, at least that allows to set the schema name in standard JPA. Check the JavaDoc for Java EE 7 or Java EE 6.
So it would be something like #JoinTable(name = "master_to_videos", schema = "test" ), and you could also specify the name of the join column if required.
Hibernate will create the table in whichever persistence.xml the entity is defined in. So if MasterTable and VideoEntity are both in persistence.xml, it will create both tables in the configured data schema.
I agree with Hein Blöd i tested the #joinTable annotation after any other annotation like #ManyToOne #OneToMany ... as for your example it becomes like this
#OneToMany
#JoinTable(schema = "testSchema" )
private List<VideoEntity> videos;
testSchema is interpreted by Hibernate as test-schema
i know this is for an old question i'm writing this so that any one
right now can find the correct answer i search the internet and this is the first question i found.

#GeneratedValue polymorphic abstract superclass over MySQL

In a Spring MVC application using Hibernate and MySQL, I have an abstract superclass BaseEntity that manages the values of the IDs for all the other entities in the model. The id field uses #GeneratedValue. I am encountering a problem whenever my code tries to save any of the subclasses that extend BaseEntity. The problem comes with the choice of GenerationType for the #GeneratedValue.
At every place in my code where a subclass of BaseEntity tries to save to the underlying MySQL database, I get the following error:
ERROR SqlExceptionHelper - Table 'docbd.hibernate_sequences' doesn't exist
I have read many postings about this on SO and on google, but they either deal with other databases (not MySQL) or they do not deal with abstract superclasses. I cannot solve the problem by using GenerationType.IDENTITY because I am using an abstract superclass to manage id fields for all entities in the model. Similarly, I cannot use GenerationType.SEQUENCE because MySQL does not support sequences.
So how do I solve this problem?
Here is the code for BaseEntity.java:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
protected Integer id;
public void setId(Integer id) {this.id = id;}
public Integer getId() {return id;}
public boolean isNew() {return (this.id == null);}
}
Here is an example of the code for one of the entities that extends BaseEntity:
#Entity
#Table(name = "ccd")
public class CCD extends BaseEntity{
//other stuff
}
Here is the DDL:
CREATE TABLE IF NOT EXISTS ccd(
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
#other stuff
)engine=InnoDB;SHOW WARNINGS;
Here is the JPQL code in the DAO:
#Override
#Transactional
public void saveCCD(CCD ccd) {
if (ccd.getId() == null) {
System.out.println("[[[[[[[[[[[[ about to persist CCD ]]]]]]]]]]]]]]]]]]]]");
this.em.persist(ccd);
this.em.flush();
}
else {
System.out.println("]]]]]]]]]]]]]]]]]] about to merge CCD [[[[[[[[[[[[[[[[[[[[[");
this.em.merge(ccd);
this.em.flush();
}
}
EDIT:
The reason I cannot use #MappedSuperClass in this situation is that I need to have ManyToOne relationships that allow for multiple subtypes to be used interchangeably. Look at the AccessLog class below as an example. It has an actor_entity and a target_entity. There can be many types of actor entities and many types of target entities, but they all inherit from BaseEntity. This inheritance enables the underlying accesslogs data table in MySQL to just have one actor_entity_id field and just one target_entity_id field instead of having to have several fields for each. When I change #Entity above BaseEntity to #MappedSuperClass, a different error gets thrown indicating that AccessLog cannot find BaseEntity. BaseEntity needs #Entity annotation in order for AccessLog to have polymorphic properties.
#Entity
#Table(name = "accesslogs")
public class AccessLog extends BaseEntity{
#ManyToOne
#JoinColumn(name = "actorentity_id")
private BaseEntity actor_entity;
#ManyToOne
#JoinColumn(name = "targetentity_id")
private BaseEntity target_entity;
#Column(name="action_code")
private String action;
//getters, setters, & other stuff
}
SECOND EDIT:
As per JBNizet's suggestion, I created a hibernate_sequences table as follows:
CREATE TABLE IF NOT EXISTS hibernate_sequences(
sequence_next_hi_value int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
)engine=InnoDB;SHOW WARNINGS;
But now I am getting the following error:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'sequence_name' in 'where clause'
Here is the hibernate sql causing the error, followed by the next 2 lines of the stack trace:
Hibernate: select sequence_next_hi_value from hibernate_sequences where sequence_name = 'BaseEntity' for update
ERROR MultipleHiLoPerTableGenerator - HHH000351: Could not read or init a hi value
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'sequence_name' in 'where clause'
How do I resolve this?
What a mess... AUTO_INCREMENT is MySQL's hidden sequence. The radical problem is that MySQL can not insert and return the PK at the same time, but Hibernate need this while INSERTing a new Entity.
The Problems you run into:
If Hibernate save a new Entity, he try to immerdentelly set the id to the new EntityBean. Therefore hibernate must read what ID will the Database use before hibernate save the new Tuple to the Table.
If you have multiple Servers who access the database, you shall let hibernate's session-factory decide to use the built-in sequence(AUTO-INCREMENT) or let hibernate decide (GenerationType.AUTO/GenerationType.IDENTITY) how large the open range of reserved PK's is (Job of a DB-Architect). (We have about 20 servers to one Database, so on a good-used table we use a PK-distance of +100). If only one server have access to the database GenerationType.TABLE shall be correct.
Hibernate must calculate the next id by yourself using max(*)+1 but:
What if two requests ask for max(*)+1 at the same time/with the same result? Right: The last try to insert will fail.
So you need to have a Table LAST_IDS in the database who stores the last Table-PK's. If you like to add one, you must do this steps:
Start read-optimistic transaction.
SELECT MAX(address_id) FROM LAST_IDS
store the maximum in a java-variable i.e.: $OldID.
$NewID = $OldID + 1. (+100 in pessimistic-lock)
UPDATE LAST_IDS SET address_id= $newID WHERE address_id= $oldID?
commit the read-optimistic transaction.
if commit was successfull, store $newID to setID() in the HibernateBean you like to save.
Finally let Hibernate call the insert.
This is the only way i know.
BTW: Hibernate-Entitys shall only use inheritance if the Database support inheritance between tables like PostgreSQL or Oracle.
Because you use the TABLE identifier generator you need to have that table created. If you are not using the enhanced identifier generators, chances are you are going to use the MultipleHiLoPerTableGenerator.
The MultipleHiLoPerTableGenerator can use one table for all table identifier generators.
My suggestion is to grab the table ddl from your integration tests, in case you use hbmddl to build the test schema. If you use flyway or liquibase for testing, you can add a maven plugin to generate the ddl schema.
Once you have the schema, you need to take the exact create table command and make add it to your MySQL database.

How to manage empty entities and/or entities with no tables using discriminators/inheritance

I've asked a few times on other sites (and here) but I figure I would try again because I really haven't found an answer. I'm sorta new to hibernate, and I'm scared of posting in hibernate's forums. I'm using mainly JPA annotations with Hibernate 3.6.
I have the following schema:
So basically this is a legacy DB. Nomination is the central table, and I have 4 specific types of Nominations:
Coworker (which only uses NOMINATION table columns as attributes)
Team (NOMINATION + TEAM_NOM tables)
Idea (NOMINATION + IDEA_NOM tables)
Success (NOMINATION + SUCCESS_NOM tables)
So what I've done is use a discriminator (and inheritance) to establish their entities. For example:
Here's Entity Nomination:
#Entity(name = "Nomination")
#Table(name = "NOMINATION")
#DiscriminatorColumn(name="CATEGORY_CODE", discriminatorType = DiscriminatorType.STRING, length = 1)
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class Nomination extends AuditableEntity {
And here's how I'm coding Team, Idea and Success Entities:
#Entity(name = "TeamNom")
#Table(name = "TEAM_NOM")
#DiscriminatorValue("T")
#PrimaryKeyJoinColumn(name = "NOM_ID")
public class TeamNom extends Nomination {
Now for Coworker I did the following:
#Entity(name = "CoworkerNom")
#DiscriminatorValue("C")
#PrimaryKeyJoinColumn(name = "NOM_ID")
public class CoworkerNom extends Nomination {
As you can see I have a big problem. Hibernate is looking for a table called "CoworkerNom", but I don't have any in our DB. I have tried putting in "Nomination" as table because I was out of ideas, but logically it gives me a circularity dependency error.
So how do I approach this entity which has no table and no attributes? The other Entities are working fine obviously.
In hibernate you are going to have to create a table with the attributes for each subclass of Nomination, so you are going to have in practice this table only populated with ID's... The rationale behind this I think is so that you have the advantage that if you want to extend this subclass with specific properties in the future, you can do so without having much your annotations or schema changing.

Hibernate Annotation for Entity existing in more than 1 catalog

I have a Person entity mapped by Hibernate to a database table in a database catalog "Active". After a period of time, records in this database table in the "Active" catalog are archived/moved to an exact copy of the table in a database Catalog "History". I have the need to retrieve from both the Active and History Catalogs. Is there a better way to model this with Hibernate annotations than making an abstract class that 2 classes extend from.
This is what I have now.
#MappedSuperclass
public abstract class Person {
#Id
private Integer id;
private String name;
}
#Entity
#Table(name="Person", catalog="Active")
public class PersonActive extends Person {
}
#Entity
#Table(name="Person", catalog="History")
public class PersonHistory extends Person {
}
To my knowledge, that would be the right way to do it with annotations (you kinda have two tables so you need two entities). Then run a polymorphic query on the Person entity. I find this pretty clean by the way.
PS: Can you add a pointer on how to do this with mapping files, I'm really curious.
My thought would be to write a query to select both tables from db A and B. then create a query with hibernate and map it to your class.
example:
#Entity
#NamedNativeQuery(
name="GetAllPerson",
query="select * from A.Person inner join B.Person on A.Person.Id = B.Person.Id"
)
public class Person {
...
}
Not sure if it could work, your question made me also curious about the best way to do it :). I'll test it tonight after work and see if its any good.
I think there is a subproject of hibernate named shards. It is designed to work with multiple relational databases. If you want to use it, you may need big changes in your code.

Categories