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
Related
I want one of the fields to be ignored when called save() method. The field is gonna get populated automatically by the database and returned. It should be treated as a read-only field.
I am concerned about private Timestamp ts; field:
#Entity
#Table(name = "time_series", schema = "ms")
#IdClass(Reading.class)
public class Reading implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "name", nullable = false)
private String sensorName;
#Id
#Column(name = "ts", insertable = false, updatable = false)
private Timestamp ts;
#Column(name = "reading")
private Double value;
...
As you see, I use insertable = false, updatable = false are inside the #Column annotation, so I'd expect that ts is ignored when forming the actual SQL behind the curtain.
#Override
#Transactional(readOnly = false)
public Reading save(Reading r) {
return readingRepository.save(r);
}
ReadingRepository is basically extended Spring's CrudRepository which has save(...) method.
When I save Reading object with ts=null I get an error from Postgres:
ERROR: null value in column "ts" violates not-null constraint
because Spring Data did not actually ignore the ts field based what I see from the log:
insert into ms.time_series (ts, name, reading) values (NULL, 'sensor1', 10.0)
Clearly, I want the query to be without ts like this:
insert into ms.time_series (name, reading) values ('sensor1', 10.0)
Why is the field not being ignored?
Now if you ask me whether my database schema is okay I say yes. When I type SQL query in console without the ts everything is fine. I even tried #Generated and #GeneratedValue annotations. Name and ts are both forming a primary key for the table, however, the result is the same if I make only one of them a PK or if I add an extra surrogate ID column. Same result...
Am I overlooking something or is there maybe a bug in the Spring framework?? I am using Spring 5.1.2 and SpringData 2.1.2
Note: If I use #Transient annotation that persists the insert query correctly but then the field is being ignored completely even on read/fetch.
Many thanks for any help with this!
Try using GenericGenerator and GeneratedValue in your code.
Add the needed annotation and give values to all other members in Reading class, except ts.
Here some examples.
As you say
I get an error from Postgres
If you check the docs it states:
Technically, a primary key constraint is simply a combination of a unique constraint and a not-null constraint.
That's also true for multi-column primary keys (see here)
So, if ts is part of your primary key in the database (as the #Id indicates) it's simply not possible to insert null values in that column.
IMO Hibernate/Spring got nothing to do with that as
insert into ms.time_series (ts, name, reading) values (NULL, 'sensor1', 10.0)
should be equivalent to
insert into ms.time_series (name, reading) values ('sensor1', 10.0)
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
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)
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.
I'm trying to persist a very simple Unidirectional One to Many relationship, but EclipseLink (2.3.1) fails.
Service Class (Parent):
#Entity
#Table(name = "tbl_service2")
public class Service implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="service_id")
public long serviceID;
#Column(name="name")
public String name;
#OneToMany(cascade={CascadeType.ALL})
#JoinColumn(name="service_id", referencedColumnName="service_id")
public Set<Parameter> parameters;
}
Parameter Class (Child):
(Of course there is "service_id" foreign key field in the database, which is not represented in the class, as it's unidirectional relation).
#Entity
#Table(name = "tbl_service_parameters2")
public class Parameter implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="param_id")
public long parameterID;
#Column(name="name")
public String name;
}
And this is the code for Entity persistence:
Service service = new Service();
service.parameters = new HashSet<Parameter>();
service.name = "test";
Parameter param = new Parameter();
param.name = "test";
service.parameters.add(param);
em.persist(service);
em.flush();
I get this exception:
Internal Exception: java.sql.SQLException: Field 'service_id' doesn't have a default value
Error Code: 1364
Call: INSERT INTO tbl_service_parameters2 (name) VALUES (?)
bind => [test]
EDIT: The database field service_id has (and should have) not-null constraint, due the nature of the data.
Is this a bug or is something wrong in the code?
Use nullable = false, on #JoinColumn:
#JoinColumn(name = "service_id", nullable = false)
Try removing the not null constraint on the Parameter table's service_id field. Eclipselink will update the foreign key for unidirectional 1:m join columns in a separate statement, so you'll need to disable or delay the constraint check. Making it bidirectional will allow the fp field to be updated with the rest of the parameter data.
You can change your persistence for hibernate version<4.0 and your code will run well."Well" in reference " for one-to-many relation save/persist parent ONLY, NOT save/persist child's collection by separate task"
I was able to get it to work in Oracle by using a deferrable foreign key.
Example:
ALTER TABLE my_table ADD CONSTRAINT my_constraint_name FOREIGN KEY (my_table_column) REFERENCES foreign_key_table (foreign_key_table_column) DEFERRABLE INITIALLY DEFERRED
By default nullable is true on #JoinColumn, while persisting the data in one to many relationship, we need to make nullable as false to avoid data violation exceptions that occurs at run-time.
As I found out, in such cases, foreign key is filled in a separate statement. In my example, I used Address entity with customer_id as foreign key.
2014-07-08T20:51:12.752+0300|FINE: INSERT INTO ADDRESS (address_id, street, city, region) VALUES (?, ?, ?, ?)
bind => [10, foo, foo, foo]
2014-07-08T20:51:12.753+0300|FINEST: Execute query InsertObjectQuery(ua.test.customer.Address#28cef39d)
2014-07-08T20:51:12.757+0300|FINEST: Execute query DataModifyQuery(sql="UPDATE ADDRESS SET customer_id = ? WHERE (address_id = ?)")
2014-07-08T20:51:12.757+0300|FINE: UPDATE ADDRESS SET customer_id = ? WHERE (address_id = ?)
bind => [151, 10]
Therefore, having #JoinColumn with nullable=true causes an error.
As alternative, you can use #OneToMany (..., orphanRemoval = true, ...).