I have two tables:
part {
int id; --> primary key, auto generated
varchar poNo;
varchar partNo;
varchar partDesc;
varchar eccNo;
...
}
supplement {
int id; --> primary key
varchar poNo; --> foreign key
varchar partNo; --> foreign key
varchar venderPartNo;
varchar exportHSCCode;
...
}
I defined one Entity as below:
#Entity
#Table(name="part")
#SecondaryTable(name="supplement", pkJoinColumns ={#PrimaryKeyJoinColumn="id"})
public class Part{
#Id
#GeneratedValue
private Integer id;
private String poNo;
private String partNo;
private String partDesc;
private String eccNo;
#Column(table="supplement")
private String vernderPartNo;
#Column(table="supplement")
private String exportHSCCode;
...
getter and setter...
}
Question 1:
when I persist one part, I dob't want to insert one row into supplement table, is there has any configuration or annotation can get it? Because according to above Entity and configuration , when I persist one part, hibernate will generate two insert SQL statement for me:
insert into part(poNo, partNo, partDesc, eccNo) values (?,?,?,?)
insert into supplement(vernderPartNo, exportHSCCode, id) vaules (?,?,?)
which I want is, when persist one part, I didn't set value for any filed of supplement, then just one insert statement:
insert into part(poNo, partNo, partDesc, eccNo) values (?,?,?,?)
is it possible?
Question 2:
from the table schema of above, the poNO and partNo is the foreign key, that means , for every related part and supplement, this two field should be has the same value. But I don't know how to map this two column value to supplement table when using the configuration as above.
As for the normal operation for Hibernate, when it process one part, it always generate two insert statement which I mentioned above, and for the secondary table, it's insert statement just contains those fields which has specified it's table name, so for supplement, it's insert statement is :
insert into supplement(vernderPartNo, exportHSCCode, id) vaules (?,?,?)
So, is there has any way to let Hibernate generate the insert statement as below:
insert into supplement(poNo, partNo, vernderPartNo, exportHSCCode, id) vaules (?,?,?,?,?)
to map two tables with #SecondaryTable
you can use like below on the primary table
#Table(name = "Table_Primary", schema = "schema ")
#SecondaryTable(name = "Table_Secondary", schema = "schema ", pkJoinColumns = {#PrimaryKeyJoinColumn(name = "Table_Primary_Column", referencedColumnName = "Table_Secondary_Column")})
1) Try the following (I would expect this to work, but Hibernate may not play this way):
#Entity
#Table(name="part")
#SecondaryTable(name="supplement", pkJoinColumns ={#PrimaryKeyJoinColumn="id"})
public class Part{
#Id
#GeneratedValue
private Integer id;
private String poNo;
private String partNo;
private String partDesc;
private String eccNo;
#Column(table="supplement")
#Basic(optional=true)
private String vernderPartNo;
#Column(table="supplement")
#Basic(optional=true)
private String exportHSCCode;
...
getter and setter...
}
2) You'll need to change how your keying Part. You've defined its primary key as an auto incremented integer...that's gonna be your foreign key in the supplement table. This is actually how JPA wants you to do it (I say that because the JPA specification calls natural keys "legacy"). You have a couple options here:
remove the autoincrement from the Part entity and create a "composite key" class with just the poNo and partNo, and add that class as a field to Part. This will become your Part primary key, and will be the foreign key used in your supplement table.
Forget foreign keys and instead add a #UniqueConstraint to your Part for those two columns (this isn't going to fix your foreign key issue, but it does enforce the constraint you identified)
Related
Helllo, I've been trying to create an Entity named ContratoAluguer, however each time I try to create this Entity the following error occurs:
Internal Exception: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "ID"; SQL statement:
INSERT INTO CONTRATOALUGUER (CLIENT_ID, AUTOMOVEL_ID) VALUES (?, ?) [23502-200]
Error Code: 23502
Call: INSERT INTO CONTRATOALUGUER (CLIENT_ID, AUTOMOVEL_ID) VALUES (?, ?)
bind => [2 parameters bound]
-----------------------Entity Code Below-----------
package isep.eapli.demo_orm.domain;
import javax.persistence.*;
import java.util.List;
#Entity
public class ContratoAluguer {
#OneToOne
private Automovel automovel;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "ContratoId")
private List<CondutorAutorizado> condutorAutorizadoList;
#ManyToOne(cascade = CascadeType.ALL)
private Cliente client;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public ContratoAluguer(Automovel automovel, List<CondutorAutorizado> condutorAutorizadoList, Cliente client) {
this.automovel = automovel;
this.condutorAutorizadoList = condutorAutorizadoList;
this.client = client;
}
From error : you are trying to insert NULL value into PRIMARY KEY column, which obviously has not null constraint.
You are expecting DB to take care of generating ID for your entity - what i see from generation type strategy.
You are probably using H2 DB ? So check table definition.
Your primary key should be of type 'bigint' (http://www.h2database.com/html/datatypes.html#bigint_type).
About identity in H2, documentation says:
Identity column is a column generated with a sequence. The column declared as the identity column with IDENTITY data type or with IDENTITY () clause is implicitly the primary key column of this table. GENERATED ALWAYS AS IDENTITY, GENERATED BY DEFAULT AS IDENTITY, and AUTO_INCREMENT clauses do not create the primary key constraint automatically. GENERATED ALWAYS AS IDENTITY clause indicates that column can only be generated by the sequence, its value cannot be set explicitly. Identity column has implicit NOT NULL constraint. Identity column may not have DEFAULT or ON UPDATE expressions.
So your SQL should looks something like this :
CREATE TABLE TEST(
ID BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
...);
I ma guessing you are using JPA (from the annotations). So if you are letting JPA to generate table for you, check table in H2 console as i mentioned earlier.
This would be my first step from information you provided.
Hope this helps
I have two tables:
language
CREATE TABLE language (
id BIGSERIAL,
name TEXT NOT NULL UNIQUE,
PRIMARY KEY (id)
);
translation
CREATE TABLE translation (
id BIGSERIAL,
language_id BIGINT REFERENCES language (id),
translation_key TEXT NOT NULL,
translation_value TEXT NOT NULL,
PRIMARY KEY (id)
);
And I would like to get such entity, where translation table (primary table) joins language table by language_id from primary table. Problem: at the moment it joins by translation PK(id).
#Entity
#Table(name = "translation")
#SecondaryTable(name = "language", pkJoinColumns = #PrimaryKeyJoinColumn(name = "id"))
public class Translation {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(table = "language", name = "name")
// ON translation.language_id = language.id
private String language;
#Column(name = "translation_key")
private String translationKey;
#Column(name = "translation_value")
private String translationValue;
// getters and setters
}
Where I should specify it in my code to do it correctly?
SQL example: SELECT t.id, l.name, translation_key, translation_value FROM translation t INNER JOIN language l on t.language_id = l.id;
You cannot use #SecondaryTable for the purpose you describe.
#SecondaryTable is used when a single entity is spread across multiple tables. Each of these 'pieces' of the entity must be privately owned by the entity, and is in a one-to-one relation with every other 'piece'.
If you want a many-to-one relation between translations and languages, you need to use #ManyToOne (and create a separate Language entity) instead.
#SecondaryTable(name = "language")
this way it is going to generate value for the translation id and insert it to the language foreign key automatically if you specify pkJoinColumn it is going to relate the tables through the primary key while if you don't mention that, it would do it through the foreign key. After that you need to create a trigger and sequence for the language table id column. It should work.
I've created database of parts in MySQL by importing data from .xlsx file. Last part ID is 3717.
Now I want to insert new record with ID: 3718 into database from my webapp where ID is autogenerated, but the #GeneratedValue annotation tries to generate ID from '1' and then it throws org.springframework.dao.DataIntegrityViolationException for duplicating primary key.
How do I autogenerate IDs starting from the last part ID in the database?
#Entity
#Table(name = "parts")
public class Part {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Integer quantity;
private Double price;
public Part() {}
//getters and setters
It depends on your hibernate version. Depending on that the generationtyoe.auto will trigger one thing or another.
If what is being used is a table sequence, it is enough with you manually executing sql statement to set current value to your desired one.
If what is being used is an auto_increment table column it is enough altering table to update current increment value.
My classes look simiar to this: (Offer class)
#Entity
public class Offer {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private int id;
#ElementCollection(fetch = FetchType.LAZY)
private Set<Product> products;
...other fields
}
and Product class:
#Embeddable
public class Product {
private String name;
private String description;
private int amount;
}
The problem is when I try to persist the Offer entity and try to add two objects to Offer's Set:
Product product = new Product("ham", "description1", 1);
Product product = new Product("cheese", "description2", 1);
I receive exception:
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "offer_products_pkey"
Details: Key (offer_id, amount)=(1, 1) already exists.
I have no idea why can't I persist two embeddable objects in the Set when one of them has the same value of "amount" field? Is it treated as ID somehow?
Maybe I should not create list of embeddable objects as it is not designed to be used like this? If so - then what if I dont need an entity of Product but want to keep set of it in another entity (Offer)?
Thanks in advance for help
The issue when using a Set is that the contents must be unique, since that is the definition of a Set. The JPA provider will try to enforce this with a database constraint. In your example it adds a constraint in the form of a Primary Key the Offer_id and the int Amount, though IMHO it should be adding a constraint for all the values of Product property. The best way to see this is to enable the SQL logs and see what is going on under the covers:
Hibernate: create table Offer (id integer not null, primary key (id))
Hibernate: create table Offer_products (Offer_id integer not null, amount integer not null, description varchar(255), name varchar(255), primary key (Offer_id, amount))
Hibernate: alter table Offer_products add constraint FKmveai2l6gf4n38tuhcddby3tv foreign key (Offer_id) references Offer
The way to fix this is to make the products property of Offer a List instead of the Set:
Hibernate: create table Offer (id integer not null, primary key (id))
Hibernate: create table Offer_products (Offer_id integer not null, amount integer not null, description varchar(255), name varchar(255))
Hibernate: alter table Offer_products add constraint FKmveai2l6gf4n38tuhcddby3tv foreign key (Offer_id) references Offer
Scenario: Hibernate 3.6 with xml-based mapping, Java7, Postgresql 8.3.
I'm currently refactoring an application where I have got this scenario for the database:
main_table
id integer
other_field string
(id) PK
secondary_table
other_field string
value string
(other_field, value) PK
Basically, there's a secondary table which contains an "other_field" which is matched on the main table; I need to extract all values for a certain record in main_table and map them.
In SQL I'd use a query like:
SELECT value FROM secondary table INNER JOIN main_table ON secondary_table.other_field == main_table.other_field where main_table.id = 1;
But I don't understand how to map a collection of basic types (strings) to the Main object in Java using such a query (or a similar one if the one I propose is not hibernate friendly), so that I can have a "values" property on my mapped object, which should be a Set<String>
I think this is what you are looking for:
#Entity
public class Primary { // Main table
#Id
#Column(name="EMP_ID")
private long id;
...
#ElementCollection
#CollectionTable(
name="PRIMARY_SECONDARY",
joinColumns=#JoinColumn(name="PRIMARY_ID")
)
private Set<Secondary> phones;
...
}
#Embeddable
public class Secondary { // Secondary table
private String value;
...
}
Full example and further details.