JPA: One Table with Two different databases - java

I want to store my table in two different databases, (for example: HyperSQL and MYSQL), but I can't duplicate table annotation like this:
#Entity(name="users")
#Table(name = "users", schema = "Users#HyperSQL_pu")
#Table(name = "users", schema = "Users#Mysql_pu")
public class UserEntitie implements Serializable {}
Have any idea, how can I do this without duplicating my bean class

This is why some people have recommended not to put schema information into annotations. Use orm.xml to specify schema information (schema name, table name, column name etc), and have one orm.xml per datastore that the system is deployed to. Clearly this means one EntityManagerFactory per datastore; you cannot have one class persisted into multiple datastores with the same EntityManagerFactory
Using annotations you can only specify something once, and would have to manually edit java files to redeploy.

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.

Dynamic schema in Hibernate #Table Annotation

Imagine you have four MySQL database schemas across two environments:
foo (the prod db),
bar (the in-progress restructuring of the foo db),
foo_beta (the test db),
and bar_beta (the test db for new structures).
Further, imagine you have a Spring Boot app with Hibernate annotations on the entities, like so:
#Table(name="customer", schema="bar")
public class Customer { ... }
#Table(name="customer", schema="foo")
public class LegacyCustomer { ... }
When developing locally it's no problem. You mimic the production database table names in your local environment. But then you try to demo functionality before it goes live and want to upload it to the server. You start another instance of the app on another port and realize this copy needs to point to "foo_beta" and "bar_beta", not "foo" and "bar"! What to do!
Were you using only one schema in your app, you could've left off the schema all-together and specified hibernate.default_schema, but... you're using two. So that's out.
Spring EL--e.g. #Table(name="customer", schema="${myApp.schemaName}") isn't an option--(with even some snooty "no-one needs this" comments), so if dynamically defining schemas is absurd, what does one do? Other than, you know, not getting into this ridiculous scenario in the first place.
I have fixed such kind of problem by adding support for my own schema annotation to Hibernate. It is not very hard to implement by extending LocalSessionFactoryBean (or AnnotationSessionFactoryBean for Hibernate 3). The annotation looks like this
#Target(TYPE)
#Retention(RUNTIME)
public #interface Schema {
String alias() default "";
String group() default "";
}
Example of using
#Entity
#Table
#Schema(alias = "em", group = "ref")
public class SomePersistent {
}
And a schema name for every combination of alias and group is specified in a spring configuration.
you can try with interceptors
public class CustomInterceptor extends EmptyInterceptor {
#Override
public String onPrepareStatement(String sql) {
String prepedStatement = super.onPrepareStatement(sql);
prepedStatement = prepedStatement.replaceAll("schema", "Schema1");
return prepedStatement;
}
}
add this interceptor in session object as
Session session = sessionFactory.withOptions().interceptor(new MyInterceptor()).openSession();
so what happens is when ever onPrepareStatement is executed this block of code will be called and schema name will be changed from schema to schema1.
You can override the settings you declare in the annotations using a orm.xml file. Configure maven or whatever you use to generate your deployable build artifacts to create that override file for the test environment.

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.

Unit testing Hibernate with multiple database catalogs

I have an issue testing a Hibernate application which queries multiple catalogs/schemas.
The production database is Sybase and in addition to entities mapped to the default catalog/schema there are two entities mapped as below. There are therefore three catalogs in total.
#Table(catalog = "corp_ref_db", schema = "dbo", name = "WORKFORCE_V2")
public class EmployeeRecord implements Serializable {
}
#Table(catalog = "reference", schema = "dbo", name="cntry")
public class Country implements Serializable {
}
This all works in the application without any issues. However when unit testing my usual strategy is to use HSQL with hibernate's ddl flag set to auto and have dbunit populate the tables.
This all works fine when the tables are all in the same schema.
However, since adding these additional tables, testing is broken as the DDL will not run as HSQL only supports one catalog.
create table corp_ref_db.dbo.WORKFORCE_V2
user lacks privilege or object not found: CORP_REF_DB
If there were only two catalogs then I think it would maybe be possible to get round this by changing the default catalog and schema in the HSQL database to that one explicitly defined:
Is there any other in-memory database for which this might work or is there any strategy for getting the tests to run in HSQL.
I had thought of providing an orm.xml file which specified the default catalog and schema (overiding any annotations and having all the defined tables created in the default catalog/schema) however these overrides do not seem to be observed when the DDL is executed i.e. I get the same error as above.
Essentially, then I would like to run my existing tests and either somehow have the tables created as they are defined in the mappings or somehow override the catalog/schema definitions at the entity level.
I cannot think of any way to achieve either outcome. Any ideas?
I believe H2 supports catalogs. I haven't used them in it myself, but there's a CATALOGS table in the Information Schema.
I managed to achieve something like this in H2 via IGNORE_CATALOGS property and version 1.4.200
However, the url example from their docs did not seem to work for me, so I added a statement in my schema.xml:
SET IGNORE_CATALOGS = true;

Can I remove the discriminator column in a Hibernate single table inheritance?

We use single table inheritance for every table in our application. This allows different instances of the same application stack to work with the same DAOs while their entities might differ slightly potentially containing information unique to that instance. An abstract class defines the basic table structure and an extension defines additional columns, if needed by that instance:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "client")
public abstract class Client extends AbstractPersistable<Long> {
// ...
}
application A:
#Entity
public class ClientSimple extends Client {
private String name;
// getter, setter
}
application B:
#Entity
public class ClientAdvanced extends Client {
private String description;
// getter, setter
}
Now a DAO can work with Client objects for application A and B but application B can define additional information for its client object that may be read by a manager method unique to application B:
application A:
Client client = new ClientSimple();
clientDao.save(client);
application B:
Client client = new ClientAdvanced();
clientDao.save(client);
Unfortunately this means there is a DTYPE column in every table (or any other name that I might choose). Is there any way to get rid of this? We don't need it and it's using up DB space...
Thanks!
EDIT
Important to note: #MappedSuperclass won't work. We're using QueryDSL as our HQL abstraction layer. This requires automatically generated Query Type classes for type save querying. These however will only be generated correctly if the abstract class is annotated with #Entity.
This is neccessairy because we want to query against the abstract class Client while in truth querying ClientSimple in application A and ClientAdvanced in application B:
So in any application this will work:
query.where(QClient.client.name.equals("something");
and in application B this will work:
query.where(QClientSimple.client.description.equals("something else");
EDIT2 - boil down
It seems to boil down to this: Can I configure hibernate at deploy time to set the discriminator type for an inhertited entity to a fixed value. So going with my example a Client will always be ClientSimple in one application and ClientAdvanced in the other so that I don't have to store that information in the database?
Like I said: Each application will be an instance of the base application stack. Each application might define additional columns for their local database but ALL objects will be of the same type for that instance so we guarantee that the discriminator is always the same making it redundant in the database and a use case for hibernate configuration.
I know, this is a very old question, but I encountered this problem recently and this might prove useful to someone.
This can be done using Hibernate's #DiscriminatorFormula annotation. The following description is based on the book Java Persistence with Hibernate, section 5.1.3; the relevant part begins at page the last paragraph on page 202.
With #DiscriminatorFormula you can provide an SQL statement that determines the value of the discriminator while fetching the relevant rows from the database. In your case, it would have to be a simple string that evaluates to some arbitrarily selected value. For this to work, you need to decide upon a name that would be used for your Client entity. Suppose that you select 'GenericClient' as the name of the entity. This is the name that should appear within #Entity annotation as the value of the name attribute. So, the complete example, in your case would look like the following.
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "client")
#DiscriminatorFormula("'GenericClient'") // *1*
public abstract class Client extends AbstractPersistable<Long> {
// ...
}
// Application A
#Entity
#DiscriminatorValue("GenericClient") // *2*
public class SimpleClient extends Client {
// ...
}
// Application B
#Entity
#DiscriminatorValue("GenericClient") // *3*
public class AdvancedClient extends Client {
// ...
}
The line that is denoted by '1' is a part of the SQL snippet that will always return 'GenericClient' as its value. The subclasses of the Client should always be annotated with the #DiscriminatorValue("GenericClient"). What this means is that when Hibernate fetches the rows from the DB, the type of the object to be constructed would always be the specific subclass of Client.
If the package where the subclasses of Client reside, and the name of the subclasses are fixed:
In that case, the #DiscriminatorValue("GenericClient") on the sub-classes wouldn't be required, all you would need to do is:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "client")
#DiscriminatorFormula("'com.example.fixed.path.FixedSubClassName'")
public abstract class Client extends AbstractPersistable<Long> {
// ...
}
The subclasses wouldn't need any annotations. The discriminator-value defaults to the entity-name, which itself defaults to the fully-qualified class-name.
Note: The SQL statement inside #DiscriminatorFormula() can be any valid SQL statement for your targeted DB server.
If you never need to use both ClientSimple and ClientAdvanced in the same application you can declare Client as #MappedSuperclass rather than #Entity.
In Hibernate, Single Table per Class hierarchy would always need a discriminator column to distinguish between the entities as all classes in one hierarchy are stored in one table.
Here is an example of Hibernate Single Table per Class Hierarchy.
But you may want to consider a different Hierarchy scheme like below:
Hibernate Single Table per Subclass
Advantages
Using this hierarchy, does not require complex changes to the
database schema when a single parent class is modified.
It works well
with shallow hierarchy.
Disadvantages
As the hierarchy grows, it may result in poor performance.
The number of joins required to construct a subclass also grows.
Hibernate Single Table per Concrete class
Advantages
This is the easiest method of Inheritance mapping to implement.
Disadvantages
Data thats belongs to a parent class is scattered across a number of
subclass tables, which represents concrete classes.
This hierarchy is not recommended for most cases.
Changes to a parent class is reflected to large number of tables
A query couched in terms of parent class is likely to cause a large
number of select operations
I would suggest you to have a look at Single Table Per Subclass scheme. Although I am not sure about your exact requirement. But this may help.

Categories