Hibernate:
/* load entities.Department */ select
department0_.name as name4_0_,
department0_.id as id4_0_
from
J_DEPT department0_
where
department0_.name=?
Hibernate:
/* load one-to-many entities.Department.employees */ select
employees0_.dept as dept4_1_,
employees0_.id as id1_,
employees0_.id as id5_0_,
employees0_.dept as dept5_0_,
employees0_.name as name5_0_
from
J_EMP employees0_
where
employees0_.dept=?
Note that ID and DEPT columns are selected twice.
#Entity
#Table(name = "J_EMP")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "dept")
private Department deptNameInEmp;
}
#Entity
#Table(name = "J_DEPT")
public class Department {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
#Id
#Column(name = "name")
private String deptNameInDeptEntity;
#OneToMany(mappedBy = "deptNameInEmp")
Set<Employee> employees;
}
UPDATED:
It was done intentionally to put #GeneratedValue on non-PK. However, now I've updated as you specified.
I've copy-pasted the new queries:
Hibernate:
/* load entities.Department */ select
department0_.id as id4_0_,
department0_.name as name4_0_
from
J_DEPT department0_
where
department0_.id=?
Hibernate:
/* load one-to-many entities.Department.employees */ select
employees0_.dept as dept4_1_,
employees0_.id as id1_,
employees0_.id as id5_0_,
employees0_.dept as dept5_0_,
employees0_.name as name5_0_
from
J_EMP employees0_
where
employees0_.dept=?
I guess its still the same.
And here are the tables:
CREATE TABLE "XYZ"."J_DEPT"
( "ID" NUMBER(*,0) NOT NULL ENABLE,
"NAME" VARCHAR2(255 BYTE) NOT NULL ENABLE,
CONSTRAINT "J_DEPT_PK" PRIMARY KEY ("ID")
)
CREATE TABLE "XYZ"."J_EMP"
( "ID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(255 BYTE),
"DEPT" NUMBER NOT NULL ENABLE,
CONSTRAINT "J_EMP_PK" PRIMARY KEY ("ID"))
here is the code -i'm pasting here as it is :
#Entity
#Table(name = "J_DEPT")
public class Department {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
#Id
private Long id;
#Column(name = "name")
private String deptNameInDeptEntity;
#OneToMany(mappedBy = "deptNameInEmp")
Set<Employee> employees;
public Set<Employee> getEmployees() {
return employees;
}
}
#Entity
#Table(name = "J_EMP")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "dept")
private Department deptNameInEmp;
public Employee() {
}
And here is the test case:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
#ContextConfiguration(locations = { "classpath:test-applicationContext.xml" })
#Transactional
public class EmpTest {
#Autowired
private SessionFactory sessionFactory;
#Test
public void testDept() {
final Department find = (Department) sessionFactory.getCurrentSession()
.get(Department.class, Long.parseLong("1"));
System.out.println("find res = " + find);
}
}
Probably because of this part:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
#Id
#Column(name = "name")
private String deptNameInDeptEntity;
There is something wrong here, the GeneratedValue cannot be applied to a non PK. Did you mean:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
#Column(name = "name")
private String deptNameInDeptEntity;
If not, and if this was intentional, please explain your goal and show your table(s).
Update: I can't reproduce the problem. I copy pasted the code you provided and here is the query I get:
select
employee37x0_.id as id135_,
employee37x0_.dept as dept135_,
employee37x0_.name as name135_
from
J_EMP employee37x0_
where
employee37x0_.id=?
Works as expected.
A Google search on "hibernate duplicate aliases" reveals some (old) issues so I don't exclude anything but I couldn't find any proof of recent existing problems. Can you provide a test case (using an embedded database)?
Related
I have problem with "communication" between Spring and PostgreSQL.
My class User.java:
public static final String TABLE_NAME = "USERS";
public static final String SEQENCE = "USERS_SEQ";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long userId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "department_id")
private Department department;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organizazion_id")
private Organization organization;
Create table script for USERS:
CREATE TABLE IF NOT EXISTS USERS (
USER_ID BIGINT NOT NULL,
DEPARTMENT_ID BIGINT,
ORGANIZATION_ID BIGINT,
PRIMARY KEY (USER_ID),
FOREIGN KEY (DEPARTMENT_ID) REFERENCES DEPARTMENT(DEPARTMENT_ID),
FOREIGN KEY (ORGANIZATION_ID) REFERENCES ORGANIZATION(ORGANIZATION_ID)
);
Class Department.java
public static final String TABLE_NAME = "DEPARTMENT";
public static final String SEQENCE = "DEPARTMENT_SEQ";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long departmentId;
private String departmentName;
.
.
. //Some other columns of primitive types about department..
Create table script for DEPARTMENT:
CREATE TABLE IF NOT EXISTS DEPARTMENT (
DEPARTMENT_ID BIGINT NOT NULL,
DEPARTMENT_NAME VARCHAR(50),
PRIMARY KEY (DEPARTMENT_ID)
);
Class Organization.java
public static final String TABLE_NAME = "ORGANIZATION";
public static final String SEQENCE = "ORGANIZATION_SEQ";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long organizationId;
private String organizationName;
private String street;
private String postalCode;
private String state;
private String city;
Create table script for ORGANIZATION:
CREATE TABLE IF NOT EXISTS ORGANIZATION (
ORGANIZATION_ID BIGINT NOT NULL,
ORGANIZATION_NAME VARCHAR(50),
STREET VARCHAR(255),
POSTAL_CODE VARCHAR(50),
STATE VARCHAR(255),
CITY VARCHAR(255),
PRIMARY KEY (ORGANIZATION_ID)
);
When I run the program, the Spring create "own" columns in PostgreSQL, and it's look like:
USER_ID, DEPARTMENT_ID, ORGANIZATION_ID, DEPARTMENT_DEPARTMENT_ID, ORGANIZATION_ORGANIZATION_ID
How can I fix it ? It should be without columns
DEPARTMENT_DEPARTMENT_ID, ORGANIZATION_ORGANIZATION_ID
The annotation #Column(name = "column_name") can't be used here.
As join column you should reference the attribute in the other class:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQENCE)
#SequenceGenerator(name = SEQENCE, sequenceName = SEQENCE, allocationSize = 1)
private Long userId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "departmentId")
private Department department;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organizazionId")
private Organization organization;
I created all the entities and linked them with primary, foreign keys. In theory, when I run the program, then all these entities should be created in the database, but the problem is that they are created in the wrong order.
For example, first the "orders" label is created, and then the "users" label, and because of this it is impossible to link them using the primary key.
Hence the question, how to make it so that hibernate understands in what order to create tables
Tables are created in the sequence shown below
Error
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table orders (id bigint not null, address varchar(255), create datetime, status varchar(255), sum decimal(19,2), updated datetime, user_id bigint, primary key (id)) engine=MyISAM" via JDBC Statement
Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'create datetime, status varchar(255), sum decimal(19,2), updated datetime, user_' at line 1
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/shop?useSSL=false&serverTimezone=UTC
spring.datasource.username=bestuser
spring.datasource.password=bestuser
spring.flyway.baseline-on-migrate=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
Bucket
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "buckets")
public class Bucket {
private static final String SEQ_NAME = "bucket_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
#OneToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToMany
#JoinTable(name = "buckets_products", joinColumns = #JoinColumn(name = "bucket_id"), inverseJoinColumns = #JoinColumn(name = "product_id"))
private List<Product> products;
}
Category
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "categories")
public class Category {
private static final String SEQ_NAME = "categories_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
private String title;
}
Order
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "orders")
public class Order {
private static final String SEQ_NAME = "orders_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
#CreationTimestamp
private LocalDateTime create;
#UpdateTimestamp
private LocalDateTime updated;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
private BigDecimal sum;
private String address;
#OneToMany(cascade = CascadeType.ALL)
private List<OrderDetails> details;
#Enumerated(EnumType.STRING)
private OrderStatus status;
}
OrderDetails
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "orders_details")
public class OrderDetails {
private static final String SEQ_NAME = "order_details_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
#ManyToOne
#JoinColumn(name = "order_id")
private Order order;
#ManyToOne
#JoinColumn(name = "product_id")
private Product product;
private BigDecimal amount;
private BigDecimal price;
}
OrderStatus
public enum OrderStatus {
NEW, APPROVED, CANCELED, PAID, CLOSED
}
Product
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "products")
public class Product {
private static final String SEQ_NAME = "product_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
private String title;
private BigDecimal price;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "products_categories", joinColumns = #JoinColumn(name = "product_id"), inverseJoinColumns = #JoinColumn(name = "category_id"))
private List<Category> categories;
}
Role
public enum Role {
CLIENT, MANAGER, ADMIN
}
User
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "users")
public class User {
private static final String SEQ_NAME = "user_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
private String name;
private String password;
private String email;
private boolean active;
#Enumerated(EnumType.STRING)
private Role role;
#OneToOne(cascade = CascadeType.REMOVE)
private Bucket bucket;
}
you can use #Temporal This annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar
see What is the use of the #Temporal annotation in Hibernate?
Put a annotation on each date or time field as follows :
#Temporal(TemporalType.TIMESTAMP)
or
#Temporal(TemporalType.DATE)
or
#Temporal(TemporalType.TIME)
You can't achieved table creation sequence by hibernate. You can use migration script tool, like Flyway or Liquibase
And your application.properties (flyway sample) set next properties
spring.flyway.url=
spring.flyway.user=
spring.flyway.password=
spring.flyway.schemas=public
spring.flyway.locations=classpath:/your/path
spring.jpa.hibernate.ddl-auto=validate
I am trying to save data in two table using OneToOne mapping.I have followed
this,this,this,this and few more online resources to accomplish this, but it is throwing
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
Creating a table where column TESTID is foreign key. In the parent table TESTID is primary key.That primary key is generated using sequence generator
CREATE TABLE EW_TEST_REFTABLE (
ID int NOT NULL PRIMARY KEY,
TESTNAME VARCHAR2(20) NOT NULL,
TESTID int,
CONSTRAINT test_id FOREIGN KEY(TESTID)
REFERENCES EW_TESTDATA(TESTID)
);
Ew_testdataEntity.java (Entity class of parent table)
#Entity
#Table(name = "EW_TESTDATA")
public class Ew_testdata {
#Id
#SequenceGenerator(name = "sube_seq",
sequenceName = "EW_TESTDATA_SEQ",
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sube_seq")
#Column(name = "TESTID")
private int testid;
#Column(name = "TESTNAME")
private String testname;
// Ew_test_reftable is another entity class.In that table the column
// TESTID (foreign key) must be same as the primary key of this
// entity/table(EW_TESTDATA)
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_test_reftable ewtestreftable;
//Constructor
// getter & setter
}
Ew_test_reftable.java
#Entity
#Table(name = "EW_TEST_REFTABLE")
public class Ew_test_reftable {
#Id
#SequenceGenerator(name = "subf_seq", sequenceName = "EW_REF_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "subf_seq")
#Column(name = "ID")
private int id;
#Column(name = "TESTNAME")
private String testname;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
//Constructor,getter & setter
}
Service to save data using Jpa
#Override
public Ew_testdata ew_testdata(String name) {
Ew_test_reftable ew_test_reftable = new Ew_test_reftable();
ew_test_reftable.setTestname("test");
Ew_testdata ew_testdata = new Ew_testdata();
ew_testdata.setTestname(name);
ew_testdata.setEwtestreftable(ew_test_reftable);
iew_tEst.ewTestdata(ew_testdata);
return null;
}
The problem seems to be similar to few other problem described in SO but still i am not able to figure out where I am making mistake
Your entity and table structure looks opposite, and that making so much confusion to understand.
Now, referring to exception
ORA-02291: integrity constraint (TableName.TEST_ID) violated - parent key not found
This mean, you don't have reference of parent id in child table when adding new row to child table.
In Ew_test_reftable class, you have
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
If I understand correctly, testid is your foreign key in EW_TEST_REFTABLE, then why are you using GenerationType.IDENTITY ? This will create new sequence id and may not match with parent key and result in error/exception.
As per my understanding of your design,
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TESTID")
private int testid;
change to
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "TESTID",unique = true)
private Ew_testdata ew_testdata;
And similar to above code should be removed from Ew_testdata entity (There might be slight change here and there)
See code below for my 2 entity classes - when I call the findAll() method from my OrigRepository class, it joins these two tables using both primary keys. I want the join to be between the primary key of the Orig table and the foreign key entry in the MsgResponse table ("OrigID") - any sugggestions?
Orig Entity
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private MsgResponse responseInfo;
}
MsgResponse Entity
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
#Column(name = "OrigID")
private int OrigId;
#OneToOne(mappedBy="responseInfo")
private Orig OrigInfo;
}
I suggest you to see the jpa documentation
here.
Example 1 should be your case
Try to swap relation ownership, that is:
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(mappedBy="origInfo")
private MsgResponse responseInfo;
}
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
// #Column(name = "OrigID")
// private int origId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private Orig origInfo;
}
Note that the #JoinColum annotation is in now in the MsgResponse entity. This is because in a #OneToOne the join column refers to the source entity (see here).
Hope this could help.
This are my entities:
public class Account extends AbstractEntity<Long> {
#Id
#SequenceGenerator(name = "accountSequence", sequenceName = "SQ_ACCOUNTS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accountSequence")
#Column(name = "ACC_ID", nullable = false)
private Long id;
...
}
public class Integration extends AbstractEntity<Long> {
#Id
#SequenceGenerator(name = "integrationSequence", sequenceName="SQ_INTEGRATIONS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "integrationSequence")
#Column(name = "INT_ID", nullable = false)
private Long id;
...
public void addIntegration(Integration integration) {
IntegrationAccount association = new IntegrationAccount();
// This does not help
//association.setIntAccountsPK(new IntAccountsPK(integration.getId(), this.getId()));
association.setAccount(this);
association.setIntegration(integration);
this.integrationAccounts.add(association);
integration.getIntAccountsCollection().add(association);
}
}
And this is entity for join table
#Entity
#Table(name = "INT_ACCOUNTS")
public class IntegrationAccount {
#EmbeddedId
protected IntAccountsPK intAccountsPK;
#JoinColumn(name = "ACC_ID", referencedColumnName = "ACC_ID", insertable = false, updatable = false)
#ManyToOne
private Account account;
#JoinColumn(name = "INT_ID", referencedColumnName = "INT_ID", insertable = false, updatable = false)
#ManyToOne
private Integration integration;
...
}
#Embeddable
public class IntAccountsPK implements Serializable {
#Column(name = "INT_ID", nullable = false)
private Long intId;
#Column(name = "ACC_ID", nullable = false)
private Long accId;
...
}
And when i do:
account.addIntegrations(integrations.getTarget());
account.setCustomer(customer);
accountService.save(account);
I got this in my log
Caused by: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.dhl.dcc.domain.IntegrationAccount
I dont have many knowledge about this kind of mapping, can you please tell me how to improve this mapping (entity for join table have to be preserved) and how to save account with related integrations? Thanks.
I know this question has already been marked as solved but I disagree with the accepted answer. This answer modifies the datamodel by adding a useless column (the new id) in the table INT_ACCOUNTS. There is another way to solve this problem in Hibernate without modifying the datamodel :
#Entity
#Table(name = "INT_ACCOUNTS")
public class IntegrationAccount implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "INT_ID_FK")
private Integration integration;
#Id
#ManyToOne
#JoinColumn(name = "ACC_ID_FK")
private Account account;
}
#Entity
#Table(name = "INTEGRATIONS")
public class Integration {
#Id
#SequenceGenerator(name = "integrationSequence", sequenceName = "SQ_INTEGRATIONS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "integrationSequence")
#Column(name = "INT_ID")
private Long id;
}
#Entity
#Table(name = "ACCOUNTS")
public class Account {
#Id
#SequenceGenerator(name = "accountSequence", sequenceName = "SQ_ACCOUNTS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accountSequence")
#Column(name = "ACC_ID")
private Long id;
}
You could create a ID field for your IntegrationAccount and then create a unique constraint for your two fields.
#Entity
#Table(name = "INT_ACCOUNTS",
uniqueConstraints=#UniqueConstraint(columnNames={"ACC_ID", "INT_ID"}))
public class IntegrationAccount {
#Id
private Long id;
#JoinColumn(name = "ACC_ID", referencedColumnName = "ACC_ID", insertable = false, updatable = false)
#ManyToOne
private Account account;
#JoinColumn(name = "INT_ID", referencedColumnName = "INT_ID", insertable = false, updatable = false)
#ManyToOne
private Integration integration;
...
}
Works like a charm!