JPA Tools/EclipseLink - Generate table from entities - column order - java

I'm trying to generate ddl from existing annotated entities using "JPA tools --> Generate Tables from Entities..." in Eclipse Kepler. When I run the task, I get a file with sql scripts to run. The problem is that the order of the columns in the table creation statement fails to comply with the order of the attributes in the class definition.
Example:
#Entity
#Table(name = "news", catalog = "myDatabase")
public class News implements java.io.Serializable {
private long id;
private String newsTitle;
private String newsTitle2;
private String newsText;
private Date created;
#Id
#GeneratedValue
#Column(name = "news_id", unique = true, nullable = false)
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "news_title")
public String getNewsTitle() {
return this.newsTitle;
}
public void setNewsTitle(String newsTitle) {
this.newsTitle = newsTitle;
}
#Column(name = "news_title2")
public String getNewsTitle2() {
return this.newsTitle2;
}
public void setNewsTitle2(String newsTitle2) {
this.newsTitle2 = newsTitle2;
}
#Lob
#Column(name = "news_text")
public String getNewsText() {
return this.newsText;
}
public void setNewsText(String newsText) {
this.newsText = newsText;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created")
public Date getCreated() {
return this.created;
}
public void setCreated(Date created) {
this.created = created;
}
}
Script:
CREATE TABLE myDatabase.news (
news_id BIGINT NOT NULL UNIQUE, created DATETIME, news_text LONGTEXT,
news_title VARCHAR(255), news_title2 VARCHAR(255), PRIMARY KEY (news_id))
How can I get the scripts with the order of the columns aligned with the java class?
Thank you very much
Stefano

This is not possible due to the abstraction approach in JPA. Theoretically you don't know the kind of database below nor whether the order is important there.

Related

#Formula not working in hibernate with object

I have a enum of few status value
NEW, REVIEWD, PUBLISHED, PENDING, UPDATED, SPAM, DUPLICATE, IRRELEVANT, UNPUBLISHED
I don't want to use them as enumerated so created one entity for that. For convenient I want to keep a column in entity to initialize status from enum and convert that enumerated value to a Object of status entity. for this..
I have two entity. I want to refer a column with value from another entity.
Basically I want to initialize a object with formula.
Entities are
#Entity
#Table(name = "event_status")
public class EventStatus {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="eventStatusId")
private Integer eventStatusId;
#Enumerated(EnumType.STRING)
#Column(unique = true,name="eventStatusType")
private EventStatusType eventStatusType;
public EventStatus() {
this(EventStatusType.NEW);
}
public EventStatus(EventStatusType eventStatusType) {
super();
this.eventStatusType = eventStatusType;
}
public Integer getEventStatusId() {
return eventStatusId;
}
public EventStatusType getEventStatusType() {
return eventStatusType;
}
public void setEventStatusId(Integer eventStatusId) {
this.eventStatusId = eventStatusId;
}
public void setEventStatusType(EventStatusType eventStatusType) {
this.eventStatusType = eventStatusType;
}
}
I have another entity in which I am referring object of this entity
#Entity
#Table(name = "event_")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Event implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id_")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Transient
public EventStatusType eventStatusType = EventStatusType.NEW;
#ManyToOne(fetch = FetchType.EAGER, targetEntity = EventStatus.class)
#Formula("select * from event_status where eventStatusId= 1")
private EventStatus status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public EventStatus getStatus() {
System.out.println("Event.getStatus() " + status);
return status;
}
public void setStatus(EventStatus status) {
System.out.println("Event.setStatus()");
this.status = status;
}
}
This is not giving any exception but not initializing this value.
Is it possible to initialize this EntityStatus with value of eventStatusType in Event entity
I would like to explain that based on the documentation:
5.1.4.1.5. Formula
Sometimes, you want the Database to do some computation for you rather than in the JVM, you might also create some kind of virtual column. You can use a SQL fragment (aka formula) instead of mapping a property into a column. This kind of property is read only (its value is calculated by your formula fragment).
#Formula("obj_length * obj_height * obj_width")
public long getObjectVolume()
The SQL fragment can be as complex as you want and even include subselects.
...
5.1.7.1. Using a foreign key or an association table
...
Note
You can use a SQL fragment to simulate a physical join column using the #JoinColumnOrFormula / #JoinColumnOrformulas annotations (just like you can use a SQL fragment to simulate a property column via the #Formula annotation).
#Entity
public class Ticket implements Serializable {
#ManyToOne
#JoinColumnOrFormula(formula="(firstname + ' ' + lastname)")
public Person getOwner() {
return person;
}
...
}
Also, we should use insertable = false, updatable = false, because such mapping is not editable

Hibernate: How to join two tables with one of it doesn't have an id?

My two tables (in SQL Server):
create table cluster (
id bigint primary key identity(1,1),
name varchar(100)
)
create table cluster_member (
cluster_id bigint,
member_name varchar(100)
)
The table cluster_member doesn't have an id. The column cluster_id is like a foreign key, reference to the id column in cluster table.
I used Hiberate Tools to generate 2 #Entity classes and a #Embeddable class. I added some class variables and #OneToMany and #ManyToOne annotations trying to join the two tables. But I got an error saying:
org.hibernate.MappingException: Foreign key (FK_hk6sas3oycvcljwbjar7p9ky3:cluster_member [cluster_id,member_name])) must have same number of columns as the referenced primary key (cluster [id])
The error message is pretty clear. But I don't know how to fix it. Please help.
Here is my code:
Cluster.java:
#Entity
#Table(name = "cluster" )
public class Cluster implements java.io.Serializable {
private long id;
private String name;
private Set<ClusterMember> members;
#Id
#Column(name = "id", unique = true, nullable = false)
public long getId() {
return this.id;
}
#Column(name = "name", length = 100)
public String getName() {
return this.name;
}
#OneToMany(mappedBy = "id")
public Set<ClusterMember> getMembers() {
return members;
}
}
ClusterMember.java:
#Entity
#Table(name = "cluster_member" )
public class ClusterMember implements java.io.Serializable {
private ClusterMemberId id;
private Cluster cluster;
#EmbeddedId
#AttributeOverrides({ #AttributeOverride(name = "clusterId", column = #Column(name = "cluster_id")),
#AttributeOverride(name = "memberName", column = #Column(name = "member_name", length = 100)) })
public ClusterMemberId getId() {
return this.id;
}
#ManyToOne
#JoinColumn(name = "cluster_id")
public Cluster getCluster() {
return cluster;
}
}
ClusterMemberId.java:
#Embeddable
public class ClusterMemberId implements java.io.Serializable {
private Long clusterId;
private String memberName;
#Column(name = "cluster_id")
public Long getClusterId() {
return this.clusterId;
}
#Column(name = "member_name", length = 100)
public String getMemberName() {
return this.memberName;
}
}
main function:
#SuppressWarnings("deprecation")
public static void main(String[] args) {
sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria("my.hibernate.table.Cluster");
criteria.add(Restrictions.like("name", "%ABC%"));
#SuppressWarnings("unchecked")
List<Cluster> clusters = criteria.list();
for (Cluster cluster: clusters) {
System.out.println(cluster.toString());
}
tx.commit();
sessionFactory.close();
}
hibernate.cfg.xml
<mapping class="my.hibernate.table.Cluster" />
<mapping class="my.hibernate.table.ClusterMember" />
Try changing this:
#OneToMany(mappedBy = "id")
public Set<ClusterMember> getMembers() {
return members;
}
to
#OneToMany(mappedBy = "cluster")
public Set<ClusterMember> getMembers() {
return members;
}
and add insertable/updatable to false on the associated ManyToOne mapping.
#ManyToOne
#JoinColumn(name = "cluster_id", insertable="false", updatable="false")
public Cluster getCluster() {
return cluster;
}
Because you are not really interested in the ClusterMember.id but in the FK linking back to Cluster.
In Hibernate you cannot use the same column in to different mapping. The "ClusterMember" already uses "cluster_id" for the #Id property, hence if you plan on using for a ManyToOne association, you need to instruct Hibernate to ignore any changes to this end (inserts and updates should be ignored).
Also you can use Hibernate's #MapsId annotation, for composite identifiers with alternate associated mappings.

Why do the Oracle hibernate dialects produce invalid schemas?

In my project, I need to support multiple databases from multiple vendors (notably, Oracle, MSSQL and MySQL).
I have a class which creates .sql files for each DB type based on my annotated hibernate model classes.
I have a class MyEntity.java like this:
#Entity
#Table(name = "my_table")
public class MyEntity implements java.io.Serializable {
private Integer id;
private Date timestamp;
private String data;
public MyEntity() {
}
#Id
#SequenceGenerator(name = "my_table_seq", sequenceName = "my_table_seq")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "my_table_seq")
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "timestamp", nullable = false)
public Date getTimestamp() {
return this.timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
#Column(name = "data", length = 65535)
public String getData() {
return this.data;
}
public void setData(String data) {
this.data = data;
}
}
This class was produced by hbm2java using reverse engineering from a MySQL database. The "data" column was a TEXT and the "timestamp" column was a TIMESTAMP.
When I use the SchemaExporter class to generate SQL for other DB types (like oracle for example) it produces invalid plsql. This class (using the Oracle10gDialect produces oracle sql like this:
create table my_table (
id integer not null,
data varchar(65535),
timestamp datetime not null
);
varchar(65535) is invalid because varchars can't be that long, and datetime is apparently not a real datatype.
When using the MySQL dialect, it correctly defines "data" as a MEDIUMTEXT type.
Why does it generate invalid oracle SQL? Is there some way I can hint to hibernate that it should use a text type? Or am I going to have to extend the oracle dialect to fix up all the data types?
Note: I'm using oracle 11.2.0.2.v7 and hibernate 4.2.8.FINAL
Another Note: Similar invalid results are produced for MSSQL (varchar(65535) is invalid).
Disclaimer: I'm new to Oracle

Java Hibernate - OneToMany relationship returning a null object (annotations)

I'm currently struggling with a mapping of one to many using annotations in hibernate, whenever I get an object, the set of items returned from the related table is always null (even when I can see in the database there are corresponding relationships with data). I have some many to one relationships in the same class which are working fine.
Other unrelated code omitted for readability
I have two tables, where a single member, can have 0 or more member membership periods:
CREATE TABLE member (
member_id INT NOT NULL AUTO_INCREMENT
PRIMARY KEY (member_id)
)
CREATE TABLE member_membership_period (
member_membership_period_id INT NOT NULL AUTO_INCREMENT ,
member_id INT NOT NULL ,
test_column VARCHAR(45) NOT NULL ,
PRIMARY KEY (member_membership_period_id) ,
INDEX member_membership_period_member_idx (member_id ASC) ,
CONSTRAINT member_membership_period_member
FOREIGN KEY (member_id)
REFERENCES member (member_id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
The Member class maps to the member table:
#Entity
#Table(name="member")
public class Member implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "member_id")
private int id;
#OneToMany
#JoinColumn(name = "member_id")
#ForeignKey(name = "member_membership_period_member")
private Set<MemberMembershipPeriod> memberMembershipPeriods = new HashSet<MemberMembershipPeriod>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<MemberMembershipPeriod> getMemberMembershipPeriods() {
return memberMembershipPeriods;
}
public void setMemberMembershipPeriods(Set<MemberMembershipPeriod> memberMembershipPeriods) {
this.memberMembershipPeriods = memberMembershipPeriods;
}
}
And the MemberMembershipPeriod class maps to the member_membership_period table
#Entity
#Table(name="member_membership_period")
public class MemberMembershipPeriod implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "member_membership_period_id")
private int id;
#Column(name = "test_column")
String testColumn;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTestColumn() {
return testColumn;
}
public void setTestColumn(String testColumn) {
this.testColumn = testColumn;
}
}
My DAO
public class MemberDaoImpl extends AbstractDAO<Member> implements MemberDao {
public MemberDaoImpl(SessionFactory factory) {
super(factory);
}
#Override
public List<Member> getAllMembers() {
Query query = currentSession().createQuery("from Member");
return list(query);
}
#Override
public Member getMemberById(int id) {
return get(id);
}
}
Implementation of get(id) (Part of drop wizards hibernate package)
protected E get(Serializable id) {
return (E) currentSession().get(entityClass, checkNotNull(id));
}
Any help provided would be greatly appreciated, I'm starting to lose the will to live over this!
Other tech being used is DropWizard (which does the hibernate configuration) and MySQL
Try this. It may help you.
#Override
public List<Member> getAllMembers() {
Criteria criteria = currentSession().createCriteria(Member.class,"member");
criteria.createAlias("member.memberMembershipPeriods","period");
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return criteria.list();
}

JPA Hibernate - Mapping MySQL Composite keys to JPA (Hibernate) entities

I am trying to map the following table
CREATE TABLE Person (
p_id varchar(255) not null,
p_name varchar(255 not null,
p_post_code varchar(12) not null,
primary key (p_id, p_name),
);
Usually when i map an Entity to the above table i would do something like this (for single column primary keys):
private int p_id;
private String p_name;
private String p_post_code;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="p_id")
public Long getPId() {
return p_id;
}
public void setPId(int p_id) {
this.p_id = p_id;
}
#Column(name="p_name")
public String getPname() {
return p_name;
}
public void setPname(String string) {
this.p_name = string;
}
#Column(name="p_post_code")
public String getPostCode() {
return p_post_code;
}
public void setPostCode(String string) {
this.p_post_code = string;
}
The above works if the primary key is a single column (i.e. p_id) and the value for this column is generated in the database.
How would i modify the above to map it so that both p_id and p_name are the primary key.
Also, how would this work, if the composite key is a foreign key in another table.
I am trying to google for some examples but i cant find a simple example and most seem to be using the XML based configuration.
When using composite keys with JPA you need to use an embedded class as an id.
In your case you would have a person class and a primary key class for person:
#entity
public class Person
{
#EmbeddedId
private PersonPK key;
#Column(name="p_post_code", nullable = false)
private String p_post_code;
//....
}
#Embeddable
public class PersonPK
{
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="p_id");
private Long p_id;
#Column(name="p_name")
private String p_name;
public PersonPK(String name)
{
p_name = name;
}
//....
}
Using a class for the person's name (so the name is also a foreign key):
#entity
public class Person
{
#EmbeddedId
private PersonPK key;
#MapsId(value="p_name_id")
#ManyToOne
#JoinColumn(name = "p_name_id", referencedColumnName = "id")
private Name p_name;
#Column(name="p_post_code", nullable = false)
private String p_post_code;
//....
}
#Embeddable
public class PersonPK
{
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="p_id");
private Long p_id;
#Column(name="p_name_id")
private Long p_name_id;
public PersonPK(Name name)
{
p_name_id = name.getId();
}
//....
}
#Entity
public class Name
{
#Id
#GeneratedValue(some generation strategy here)
#Column(name="id")
private Long id;
#Column(name="name")
private String name;
//....
}

Categories

Resources