I have severals Entitys in my models but some of them share a same property namely Student i have created a abstract class like this.
#javax.persistence.MappedSuperclass
public abstract class StudentImpl
{
private Student student;
#ManyToOne(fetch=FetchType.LAZY)#JoinColumn(name="c01")
public Student getStudent(){return student;}
#Override
public void setStudent(final Student student){this.student=student;return;}
}
this is working like a sharm take a look that the 95% of them have mapped to C01 column in my MySQL table.
I have use this abstract class extending each of my Models with share the same property.
public class Teammate extends StudentImpl
The problem arise in some classes the Student property is mapped to a different column name in their table
Example
create table myTable
(
c02 int(11) NOT NULL, //student entity is mapped to c02 column instead of c01
)
As you can see they mismatch c01 and c02 and their column c01 column is mapped to a simple String instead of a Student.
I have try
#javax.persistence.AttributeOverride(name="student",column=#Column(name="c02"))
Wishing Hibernate could understand student property is mapped to column c02 in this Entity.
#javax.persistence.AttributeOverride(name="student",column=#Column(name="c02"))
public class AnotherClass extends StudentImpl
{
private String c01;
private String getC01(){return this.c01;} //Column c01 is mapped to a String
}
But seems not working because it Throws
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Column 'C01' specified twice.
This problem arise when i try to insert a new AnotherClass registry.
Why i am doing wrong is not possible accomplish it i am asking to much.
Thanks a lot and best regards from Venezuela.
Update
Solved i have find the solution thanks by #ddalton i used this and this is working
#javax.persistence.AssociationOverride(name="student",joinColumns=#JoinColumn(name="c02"))
You can use the AssociationOverride annotation to accomplish this:
http://www.objectdb.com/api/java/jpa/AssociationOverrides
Related
In C# we are using an ORM that lets us specify in each child/Sub Class where we want to store it:
[MapInheritance(MapInheritanceType.ParentTable)] //this means that store employee specific fields in person table
public partial class Employee: Person
{}
I want to use the same in Java side,But in Hibernate we specify strategy in parent Class .We have following structure: enter image description here
I don't want a table for base class.I'd like to store person & employee in user table. and customer in its own table.
But it seems that hibernate has shortcoming in this regard and asks for one hierarchy policy for all branch. I want to be able to change policy in lower branches.
How is it possible to implement this in jpa or hibernate?
You can do that using #MappedSuperclass
One #MappedSuperclass or multiple #MappedSuperclass are allowed in same inheritance hierarchy.
#MappedSuperclass
public class FirstMapped {
#Id int id;
}
#MappedSuperclass
public class SecondMapped extends FirstMapped {
String createdOn;
}
#Entity
public class MyTable extends SecondMapped {
String myColumn;
}
These classes must create just one table: MyTable with columns:
id
createdOn
myColumn
I was trying to find an answer but, unfortunately, with no luck.
The data structure looks like this:
TABLE_X - contains userId, also userType telling if this is external or internal user
INTERNAL_USERS - contains key userId
EXTERNAL_USERS - also contains key userId
TABLE_X.userId is either INTERNAL_USERS.userId or EXTERNAL_USERS.userId.
Now, I would like to map an entity out of TABLE_X and have user object mapped to correct entity, either INTERNAL_USERS or EXTERNAL_USERS.
How should I do this?
Should I create two fields and map one to INTERNAL_USERS and one two EXTERNAL_USERS and just see which one is not empty?
If I understand correctly your question, what you have to do is to replicate structure of the TABLE_X columns with fields on the TABLE_X class, and add to fields one for INTERNAL_USERS.userID and one for EXTERNAL_USERS.userID
But if you store on TABLE_X.userType if a user is internal or external, I think that the best thing you can do is not create any other table, because you just have the information you need on your first table (TABLE_X). If you want to know all the users that are internal for instance, just do a SQL and select all the values from TABLE_X where userType = "Internal"
Use Hibernate inheritance. Check out the Table per class inheritance pattern. Here you have both INTERNAL_USERS or EXTERNAL_USERS data in TABLE_X with userType as the discriminator column.
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1191
Given the table structure, you can use JPA Inheritance as detailed here:
https://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Example_joined_inheritance_annotations
In Hibernate you can model such relationships as follows. When querying for a User you can then rely on Hibernate to return an instance of the correct type.
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public class User{
#Id
private Long userId;
}
#Entity
public class InternalUser extends User{
}
#Entity
public class ExternalUser extends User{
}
As noted in the article linked to, Hibernate does not require a discriminator column to be specified when using joined inheritance. It does however support a discriminator column if one is available. As you have one available in your schema - userType - then you could explicitly specify it if you wish. I imagine this would yield some performance benefit in terms of the generated SQL:
Mappings with optional discriminator column:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="userType")
public class User{
#Id
private Long userId;
}
#Entity
#DiscriminatorValue("INT")
public class InternalUser extends User{
}
#Entity
#DiscriminatorValue("EXT")
public class ExternalUser extends User{
}
I have a next problem: I ve got a several tables in database, and somehow i need to make a query from one of them, but only in runtime i will know the name of needed table, so is any possibility to pass table name to #Table annotation of entity in runtime? All of these tables have absolutely identical schema. The only distinction - is name (BILLING_DATA_2016_1, BILLING_DATA_2015_12 etc.). Do somebody have an idea how can i pass the name of table dynamically? Or may be some hack with Queries and Inheritance?
You can try HibernateInterceptor. Place the {BILLING_DATA_PLACEHOLDER} string into your #Table annotation and just replace it on fly
public class HibernateInterceptor extends EmptyInterceptor {
#Override
public String onPrepareStatement(String sql) {
String prepedStatement = super.onPrepareStatement(sql);
prepedStatement = prepedStatement.replaceAll("{BILLING_DATA_PLACEHOLDER}", theRealSchemaName);
return prepedStatement;
}
}
Have not tried though
I am using struts, now I have a question:
Is it possible the name of BO class be different from table name in database?
when I change the name, it makes error
Check a table name associated with your object if you use annotations.
#Entity
#Table(name = "yourtablename")
public class YourClass {...}
Good Morning, my Dear comrades,
This is starting to be come annoying - a simple thing, but hours of struggle, am I getting old??
I am trying to map two Classes to a single table using JPA by Hibernate. The idea is to have only a small subset of columns in parent Class, and bigger/full set in the child Class. There is NO TABLE inheritance involved, only class inheritance.
How can this be accomplished??
Doing this will not work:
#Entity
#Table(name = "the_table")
class Parent implements Serializable {
}
#Entity
#Table(name = "the_table")
class Child extends Parent implements Serializable {
}
Hibernate assumes default inheritance strategy InheritanceType.SINGLE_TABLE, and is looking for discriminator column - DTYPE by default. But wait - there is no table inheritance, having the discriminator column does not make sence.
I have also taken a look at PolymorphismType.EXPLICIT which did not make any difference. The stack trace is:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'apprentice0_.DTYPE' in 'where clause'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2281)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1881)
yeah, one more thing:
The #MappedSuperclass and #Embeddable are of no use as these can not be used in conjunction with #Entity - the parent class has to be an #Entity itself as it is being used for persistence elsewhere.
#MappedSuperclass is the annotation that must be used. If the same class is both a mapped super class and an entity, then simply split it into two classes:
#MappedSuperclass
public class Parent {
// ...
}
#Entity
public class ParentEntity extends Parent {
// no code at all here
}
#Entity
public class Child extends Parent {
// additional fields and methods here
}
There are a couple of ways each with their own caveats.
1) Add annotations as following:
#DiscriminatorFormula("0")
#DiscriminatorValue("0")
class BaseClass{ }
#DiscriminatorValue("00")
class SubClass extends BaseClass{ }
where the subclasses discriminator value must be different to the base class' but also evaluate to the same value when passed into an Integer.valueOf(String s) method.
The caveat - if you return an object from Hibernate of the base class and then again when calling for the subclass type you will get an error complaining the loaded object was of the wrong class. If you call the subclass query first however the base class call will return the subclass.
2) Use a view in the database to map the table and use this as the table of the sub class. In fact it can be any other class that matches the column mappings as Hibernate thinks its a completely separate table.
Caveat - You will potentially have the same row instantiated as two different objects that will not be synchronised and could lead to conflicting/lost database updates.
It's probably better to stick with one type for a session and that could be handled without the runtime risks by using an entity mapping xml file that overrides the DiscriminatorValue of the desired class to match the constant Discriminator'Formula' value which you can pass into the initial configuration.
Make a view of the table with the limited set of columns and map the second class to that one. Define an interface with the limited set of columns and have both class implement the interface. That probably gets you about 95% of what you need. If you need to, create methods to define equality between the two as well as being able to convert the larger class (via a constructor?) to the smaller class.
You have to select an inheritance type for two entities.
What you are trying to do is not appropriate, because hibernate won't know what objects to instantiate.
If you simply need an object to have fewer fields, then don't map it as an entity - just provide a constructor that copies all fields from the other class.
If you don't want to add auto dtype column, you should define your own Discriminator by #DiscriminatorFormula
#Entity
#Table(name = "CS_CUSTOMER")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorFormula("case when id < 3 then 'VIP' else 'Customer' end")
public class Customer extends BaseEntity {
...
#Entity
public class VIP extends Customer {
...
The Discriminator name is default to Entity class name, if you want to change it, use
#DiscriminatorValue("VIP")
Log from hibernate
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
create table cs_customer (
id bigint not null,
create_user_id bigint,
first_name varchar(255),
last_name varchar(255),
primary key (id)
)