I have two entities
#Entity
#Table(name = "Documents")
public class Document extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(nullable = true, name = "asset_id")
private Asset asset;
#ManyToOne( targetEntity = Debt.class,
fetch = FetchType.LAZY, optional = false)
#JoinColumn(nullable = true, name = "debt__id")
private Debt debt;
}
and
#Entity
#Table(name = "debts")
public class Debt extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "debt", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Document> documents;
}
This mapping:
#ManyToOne( targetEntity = Debt.class,
fetch = FetchType.LAZY, optional = false)
#JoinColumn(nullable = true, name = "debt_id")
private Debt debt;
was recently added.
On running the app, the app is crashing with an error saying: Error executing DDL "alter table documents add debt__id bigint not null" via JDBC Statement
I checked the sql query hibernate sent to the database and it was: alter table documents add debt_id bigint not null
This query fails because there are records already on the documents table so a non-nullable column without default value could not be added.
So why is the nullable=true in the #JoinColumn annotation ignored by hibernate.
I couldn't find an answer anywhere. This is a spring-boot app, if it helps.
Just remove the optional = false from the #ManyToOne. That is the culprit. Also, you don't need to mention nullable=true in the #JoinColumn, that is by default true
#ManyToOne( targetEntity = Debt.class,
fetch = FetchType.LAZY)
#JoinColumn(name = "debt__id")
private Debt debt;
Related
I'm trying to use Hibernate to map the following relationship:
Each order contains 2 images. When I delete an order I want the images gone as well.
I have two entities, OrderItems and Image and they look like this
public class OrderItems {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Long id;
#Transient
private String language;
#OneToMany(fetch = FetchType.EAGER ,orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "order")
private List<Image> images ;
}
public class Image implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Long id;
#Column(name = "IMAGE_NAME")
private String name;
#Column(name = "IMAGE_BYTES", unique = false, nullable = true, length = 1000000)
private byte[] image;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "order_id" , nullable = false)
private OrderItems order;
}
Inserting new orders will also insert the coresponding images but when I try to delete an order I get an foreign key constraint error from the tables Image
Am I missing something about Hibernate ? Shouldn't the attribute cascade = CascadeType.ALL do the trick ?
Thanks for taking the time to provide any feedback. Cheers
I already tried OneToMany and ManyToOne unidirectional and bidirectional but I get the same foreign key violation error or my images are not saved at all when I save a new order.
I solved the issue by using Spring to delete an order and automagically it also deleted the images corresponding to that order.
So my first approach of deleting orders by executing sql queries directly on the DB was the issue.
Try like this
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
#ManyToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name = "order_id", nullable = false)
So im developing a project in which i have an entity that holds a relation to itself. Now for some reason when i try to save an entity (made in a react app sent through rest) it throws:
java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`post`.`post_sections`, CONSTRAINT `FKdg8t1aa12xxpo5bwa6ef634x2` FOREIGN KEY (`sections_id`) REFERENCES `sections` (`id`))
Now this is my entity:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Table(name = SQL.SECTION_TABLE)
#ToString(doNotUseGetters = true)
#Entity(name = SQL.SECTION_ENTITY)
#EqualsAndHashCode(doNotUseGetters = true)
public class SectionDAO implements Serializable {
#Id
#GeneratedValue(generator = "uuid2", strategy = GenerationType.AUTO)
#Column(columnDefinition = "BINARY(16)", unique = true)
#GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
private UUID id;
#ToString.Exclude
#EqualsAndHashCode.Exclude
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<SectionDAO> children = new HashSet<>();
#ToString.Exclude
#EqualsAndHashCode.Exclude
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private SectionDAO parent;
#ToString.Exclude
#ElementCollection
#EqualsAndHashCode.Exclude
private List<Translation> localizations;
}
All the others work, because i have the spring data hibernate logs and it only blows up when inserting the so called "children". Is there any reason i don't see here to justify it not working?
I would be very grateful to you for help.
I use Spring Boot 2.5.2.
DB: H2 with Liquibase
I need to change ticket History when attachment is removed.
This is my entities:
Ticket:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Ticket {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_owner_id", nullable = false)
private User owner;
#OneToMany(mappedBy = "ticket", orphanRemoval = true)
private List<Attachment> attachments;
#OneToMany(mappedBy = "ticket", orphanRemoval = true)
private List<History> history;
// other fields and relationships
}
User:
#Entity
#Table(name = "users")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "owner", orphanRemoval = true)
private List<Ticket> ownerTickets;
// other fields and relationships
}
Attachment:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Attachment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String filename;
#Column(columnDefinition = "bytea")
private byte[] file;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "ticket_id", nullable = false)
private Ticket ticket;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_id", nullable = false)
private User user;
}
History:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class History {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#CreationTimestamp
#Column(name = "changed_date", nullable = false, updatable = false)
private LocalDateTime changedDate;
private String action;
private String description;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "ticket_id")
private Ticket ticket;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_id", nullable = false)
private User user;
}
Services:
JpaAttachmentService:
#Service
#AllArgsConstructor
public class JpaAttachmentService implements AttachmentService {
private final AttachmentRepository attachmentRepository;
private final HistoryService historyService;
#Transactional
#Override
public void delete(Long id, Long ticketId, Long userId) {
var attachment = attachmentRepository.getByIdAndTicketIdAndTicketOwnerId(id, ticketId, userId);
var action = "File is removed";
var description = "File is removed: " + attachment.getFilename();
var ticket = attachment.getTicket();
var user = attachment.getUser();
var history = new History(null, LocalDateTime.now(), action, description, ticket, user);
historyService.save(history);
attachmentRepository.deleteByIdAndTicketIdAndTicketOwnerId(id, ticketId, userId);
}
}
When I try to 'historyService.save(history)' I catch:
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "USER_ID"; SQL statement:
update history set action=?, description=?, ticket_id=?, user_id=? where id=? [23502-200]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:459)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
at org.h2.message.DbException.get(DbException.java:205)
at org.h2.message.DbException.get(DbException.java:181)
at org.h2.table.Column.validateConvertUpdateSequence(Column.java:374)
at org.h2.table.Table.validateConvertUpdateSequence(Table.java:845)
at org.h2.command.dml.Update.update(Update.java:176)
at org.h2.command.CommandContainer.update(CommandContainer.java:198)
at org.h2.command.Command.executeUpdate(Command.java:251)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:191)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:152)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 144 more
This is 'var user' debug:
picture
I can't understand why I get this Hibernate Interceptor but not entity. I confused when I see inside interceptor required UserID and when I see 'null' outside of it. Could you help me with this problem, please?
Thanks in advance for any help.
The exception message is quite informative regarding the error you are experiencing. Take a look at the following part:
NULL not allowed for column "USER_ID"; SQL statement: update history
set action=?, description=?, ticket_id=?, user_id=? where id=?
What you attempt to do is to save an instance of a History entity which without passing in a reference to a User object. Since your relation dictates that the user reference cannot be null:
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_id", nullable = false)
To fix this, either make sure that a non-null reference to a User object is passed in when inserting/updating the History reference, or modify your database constraint design to allow for null user references at the History entity.
My problem was related to test, but in the further development I faced it again. So I want to share my solution.
Maybe it will help you.
Pay attention to CascadeType! Cascading operations must be specified above the link to the child relation. In my case, I have to remove this relation or leave Ticket with CascadeType.PERSIST
Fixed class Attachment:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Attachment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String filename;
#Column(columnDefinition = "bytea")
private byte[] file;
#ManyToOne(fetch = FetchType.LAZY) // or cascade = CascadeType.PERSIST
#JoinColumn(name = "ticket_id", nullable = false)
private Ticket ticket;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
private User user;
}
In my project I use Spring data jpa. I have tables for many to many relationship. My entities:
#Entity
#Table(name = "SPEC")
public class SpecJpa {
#Id
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "Creator_ID", unique = false, nullable = false, updatable = true)
private UsersJpa usersJpa;
#Column(name = "DESCRIPTION")
private String description;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="SPEC_PARTS",
joinColumns = #JoinColumn(name="ID_PARTS", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="ID_SPEC", referencedColumnName="id")
)
private Set<PartsJpa> partsJpa;
//---------------
And Parts:
#Entity
#Table(name = "PARTS")
public class PartsJpa {
#Id
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "ID_EXPORT", unique = false, nullable = false, updatable = true)
private ExportJpa exportJpa;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "ID_TYPE", unique = false, nullable = false, updatable = true)
private TypesJpa typesJpa;
#Column(name = "DESCRIPTION")
private String description;
#ManyToMany(fetch = FetchType.EAGER)
private Set<SpecJpa> specJpa;
Now in Controller I try to delete one row from table parts:
#PostMapping("deletePart")
public String deletePart(#RequestParam String id, Model model) {
partsService.deleteById(Integer.parseInt(id));
return "redirect:/parts";
}
But I have exception:
ferential integrity constraint violation:
"FK9Y4MKICYBLJWPENACP4298I49: PUBLIC.PARTS FOREIGN KEY(ID_EXPORT)
REFERENCES PUBLIC.EXPORT(ID) (1)"; SQL statement: /* delete
com.aleksandr0412.demo.entitiesjpa.ExportJpa / delete from EXPORT
where id=? [23503-200]], SQL: / delete
com.aleksandr0412.demo.entitiesjpa.ExportJpa */ delete from EXPORT
where id=? 2020-05-25 19:16:31.630 WARN 13387 --- [nio-8080-exec-4]
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23503, SQLState:
23503
In my db for this entities I have 3 tables: Parts, Spec and Spec_parts. As I understand to solve this problem, I firstly should delete rows in table spec_parts, and after this I can delete row from table parts. How can I do this?
In your partsService implementation, I would recommend you first fetch the resource you are about to delete (i.e the PartsJpa) using the given id from the controller.
Next set its specJpa to null or emptySet, then call the delete method afterwards.
For this to work, ensure that method setSpecJpa(SpecJpa specJpa) and setPartJpa(PartJpa partJpa) are properly implemented.
I hope you find this helpful.
I have 3 entities - Storage, Item and Relation. Storage has several Item entities and items are bound by Relation entities. And relations can bind items from different storage. For simplification let say I want to load relation by query and want to do it fast. So now I have 3 query - loading for Storage, loading for all Items under storage and load of relation (List<Relation> relations field).
Now I want to tell hibernate how to load Collection<Relation> extRelation field. I tried #Formula, #CalculatedColumn and different combination of #ManyToMany and #JoinFormula. But generated query is wrong (or ignores my query). Also I cannot use #OneToMany because of https://hibernate.atlassian.net/browse/HHH-9897 bug.
Latest Exception is:
Caused by: org.h2.jdbc.JdbcSQLException: Table
"TEST_STORAGES_TEST_RELATIONS" not found; SQL statement:
SELECT extrelatio0_.test_storages_storage_id AS test_sto1_2_0_
,extrelatio0_.extRelation_from_item_id AS extRelat2_3_0_
,extrelatio0_.extRelation_to_item_id AS extRelat3_3_0_
,relation1_.from_item_id AS from_ite1_1_1_
,relation1_.to_item_id AS to_item_2_1_1_
,relation1_.relation_id AS relation3_1_1_
,relation1_.storage_id AS storage_4_1_1_
FROM test_storages_test_relations extrelatio0_
INNER JOIN test_relations relation1_ ON extrelatio0_.extRelation_from_item_id = relation1_.from_item_id
AND extrelatio0_.extRelation_to_item_id = relation1_.to_item_id
WHERE extrelatio0_.test_storages_storage_id = ?
My entities:
#Entity
#Table(name = "test_storages")
public class Storage {
#Id
#Column(name = "storage_id")
private BigInteger storageId;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, targetEntity = Item.class)
#JoinColumn(name = "storage_id", updatable = false)
#MapKey
private List<Item> items;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, targetEntity = Relation.class)
#JoinColumn(name = "storage_id", updatable = false)
#Fetch(org.hibernate.annotations.FetchMode.SELECT)
private List<Relation> relations;
#ManyToMany()
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula =
#JoinFormula(
value = "(select dep.from_item_id, dep.to_item_id from test_relations dep where dep.storage_id = ?)"
)
)
})
private Collection<Relation> extRelation;
}
#Entity
#Table(name = "test_items")
public class Item {
#Id
#Column(name = "item_id")
private BigInteger itemId;
private String name;
#Column(name = "storage_id")
private BigInteger storageId;
}
#Entity
#Table(name = "test_relations")
public class Relation {
#Column(name = "relation_id")
private BigInteger relationId;
#Column(name = "storage_id")
private BigInteger storageId;
#EmbeddedId
private RelationPK pk;
}
#Embeddable
public class RelationPK implements Serializable {
#Column(name = "from_item_id")
private BigInteger fromItemId;
#Column(name = "to_item_id")
private BigInteger toItemId;
}
All sources available on https://github.com/ainlolcat/test_hibernate_formula