I'm auto generating entities within the database which works great using:
spring.jpa.hibernate.ddl-auto=update
Now I need an additional attribute within the association table and I can't figure it out without creating an association entity by hand. The current classes listed below generate an association table without the additional attribute.
The tables I need:
persons:
id
search_requests:
id
search_requests_persons:
person_id
search_request_id
study_id
The classes I currently have (simplified):
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "persons")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
// The following line is what I would need
// private List<Integer> studyIds;
}
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "search_requests")
public class SearchRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
#NonNull
#ManyToMany
private List<Person> persons;
}
I'm using Lombok and Javax Persistence for the annotations.
In order to add additional attributes in your JoinTable, you could manually create your JoinTable entity. e.g:
PersonSearchRequest.java
#Entity
#Table(name = "person_search_request)
#Getter
#Setter
#NoArgsConstructor
public class PersonSearchRequest {
#EmbeddedId
private PersonSearchRequestPK id;
// put your additional attribute here, e.g:
private String attribute1;
private Long attribute2;
#ElementCollection
private List<String> attribute3s;
#Embeddable
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public static class PersonSearchRequestPK implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
private Person person;
#ManyToOne(fetch = FetchType.LAZY)
private SearchRequest searchRequest;
}
}
Person.java
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "persons")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
#OneToMany(mappedBy = "id.person")
private List<PersonSearchRequest> personSearchRequests;
}
SearchRequest.java
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "search_requests")
public class SearchRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
#OneToMany(mappedBy = "id.searchRequest")
private List<PersonSearchRequest> personSearchRequests;
}
Related
JPA Model:
#Getter
#Setter
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "BASE_RECORD")
public class BaseRecord {
#Id
#Column(name = "DB_ID")
public Long id;
#Embedded
public DeclarantRecord declarant;
}
#Getter
#Setter
#Embeddable
#AllArgsConstructor
#NoArgsConstructor
public class DeclarantRecord {
#Column(name = "DECLARANT_ID")
public String declarantId;
#Column(name = "DECLARANT_IDE")
public String identificationNumber;
#Column(name = "DECLARANT_NAME")
public String name;
#OneToMany(mappedBy = "baseRecord", fetch = FetchType.EAGER)
public List<DeclarantAddress> addresses;
}
#Getter
#Setter
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "ADDRESS_RECORD")
public class DeclarantAddress {
#Id
#Column(name = "DB_ID")
public Long id;
#ManyToOne
#JoinColumn(name = "PERS_ID", referencedColumnName = "DECLARANT_ID")
public BaseRecord baseRecord;
}
When fetching a BaseRecord from DB by using a Spring Boot JPARepository, I receive the following exception:
Caused by: org.hibernate.AnnotationException: referencedColumnNames(DECLARANT_ID) of DeclarantAddress.baseRecord referencing BaseRecord not mapped to a single property
I cannot understand what's wrong and moreover, if I inline the DeclarantRecord in the BaseRecord entity by declaring all the properties in there and moving the exact same relationship declaration in the BaseRecord class, everything works perfectly.
The answer that worked for me:
Move
#Column(name = "DECLARANT_ID") public String declarantId; to BaseRecord class.
The rest can stay the same.
I have this problem where trying to delete a parent object via crud repository, I'm getting this error message:
"collection owner not associated with session: ClassA.things"
This error appeared after splitting one class into three (two classes extend the main classA), but I haven't done any other changes, I haven't touched this OneToMany relationship. So right now it looks approximately like this:
Class A:
#Table
#Entity(name = "ClassA")
#Inheritance(strategy = InheritanceType.JOINED)
#Getter #Setter #NoArgsConstructor #ToString
public class ClassA {
#Column(name = "ClassA_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToMany(mappedBy = "classA", orphanRemoval = true)
private Collection<Thing> things;
...etc, other fields
}
Class B and C (both extend class A):
#Table
#Entity(name = "ClassB")
#Getter #Setter #NoArgsConstructor
public class ClassB extends ClassA {
#Column(name = "ClassB_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...etc, other fields
}
#Table
#Entity(name = "ClassC")
#Getter #Setter #NoArgsConstructor
public class ClassC extends ClassA {
#Column(name = "ClassC_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...etc, other fields
}
And here's the Thing class, which the ClassA has a collection of with #OneToMany relationship:
#Table
#Entity(name = "Ratings")
#Getter #Setter #NoArgsConstructor
public class Thing {
#Column(name = "Thing_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(value = AccessLevel.PRIVATE)
private int id;
#ManyToOne
#JoinColumn(name = "ClassA_id")
private ClassA classA;
...etc, other fields
}
Finally, here's the controller method where DELETE is being called to delete ClassB, for example:
#Transactional
#DeleteMapping("/delete/{id}")
public ResponseEntity<String> deleteClassB(#PathVariable(name = "id") int id) {
if (classBservice.delete(id)) {
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}
try to remove the id members from ClassB and ClassC since they are inherited from ClassA.
I have the following embeddable
#Data
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class BaseEntity {
#CreatedDate
#Column(name = "created_date")
private LocalDateTime createdDate;
}
Which I embedded into another entity like this
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "room")
#Builder
public class room {
#Id
#GeneratedValue
private UUID id;
#JsonUnwrapped
#Embedded
private BaseEntity baseEntity;
#Column(length = 80, nullable = false)
private String name;
}
Now when I save a room entity the embedded BaseEntity is null and that is why nothing is audited. According to https://docs.spring.io/spring-data/commons/docs/2.4.4/reference/html/#auditing.annotations it should just work like this. How can I fix this behaviour ?
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "room")
#Builder
public class room {
...
#JsonUnwrapped
#Embedded
private BaseEntity baseEntity = new BaseEntity();
...
}
I have 2 tables, products, and product_photos. I need to insert data to both tables in one transaction.
#Entity
#Table(name = "products", schema = "my_schema")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
...
//getter + setter + constructor
}
#Entity
#Table(name = "product_photos", schema = "my_schema")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class ProductPhoto {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "product_id")
private Integer productId;
...
}
}
Is there a way to retrieve the id of the Product before writing the entity to DB in order to put it on ProductPhoto (column product_id)?
Is this possible? Haven't seen much discussion on it.
Sure! It works great from my experience. Here's an example entity:
#Entity
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class PingerEntity {
// ID
#Id
#Getter
#Setter
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// USER
#Getter
#Setter
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private UserEntity user;
// URL
#Getter
#Setter
#Basic(optional = false)
private String url;
/**
* The number of seconds between checks
*/
#Getter
#Setter
#Basic(optional = false)
private int frequency;
#Getter
#Setter
#Basic(optional = false)
#Enumerated(EnumType.STRING)
public MonitorType monitorType;
}
You can use it also with #Data (and it works !)
#Entity
#Data
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
}
I have never tried Lombok with Hibernate but I don't see why it shouldn't work.
Also, take a look here: http://groups.google.com/group/project-lombok/browse_thread/thread/294bd52d9d8695df/7bc6b0f343831af1?lnk=gst&q=hibernate#7bc6b0f343831af1
Also, Lombok project release notes mention Hibernate explicitely.
A simple example; Library.java:
#Data
#NoArgsConstructor // JPA
#Entity
#Table(name = "libraries")
public class Library {
#Id
#GeneratedValue
private Long id;
#OneToMany(cascade = CascadeType.ALL)
#EqualsAndHashCode.Exclude
// This will be included in the json
private List<Book> books = new ArrayList<>();
#JsonIgnore
public void addBook(Book book) {
books.add(book);
book.setLibrary(this);
}
}
And Book.java:
#Data
#NoArgsConstructor // JPA
#Entity
#Table(name = "books")
public class Book {
#Id
#GeneratedValue
private Long id;
#NotBlank
private String title;
#ManyToOne
#JoinColumn(name = "library_id") // Owning side of the relationship
#EqualsAndHashCode.Exclude
#JsonIgnore // Avoid infinite loops
private Library library;
}