Unable to use #NamedEntityGraph with #ElementCollecion - java

I'm trying to set simple entity with NamedEntityGraph on it. Unfortunately it won't work. Could you have any ideas how to fix it?
ServiceType entity has #ElementCollection of with Set of String which are simply ids of PictureModel associated with entity. On run I got:
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [backgroundPicIds] on this ManagedType [pl.mihome.djcost.model.ServiceType]
#Entity
#Table(name = "service_type")
#Getter
#Setter
#NoArgsConstructor
#NamedEntityGraph(
name = "serviceType.with.backgroundPicIds",
attributeNodes = #NamedAttributeNode("backgroundPicIds")
)
public class ServiceType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
#Column(nullable = false, updatable = false)
private int id;
#Length(max = 100)
#NotBlank
private String name;
private boolean active;
#OneToMany(mappedBy = "serviceType")
private Set<Account> accounts;
#ManyToMany(mappedBy = "servicesApplicable")
private Set<AccountType> accountTypes;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "serviceType", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<PictureModel> backgroundPicture;
#ElementCollection
#CollectionTable(name = "image", joinColumns = {#JoinColumn(name = "service_type_id")})
#Column(name = "id")
private Set<String> backgroundPictureId;
#PrePersist
void activate() {
this.active = true;
}
}
#Entity
#Table(name = "image")
#NoArgsConstructor
#Getter
#Setter
#Builder
#AllArgsConstructor
public class PictureModel {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(nullable = false, updatable = false)
#Setter(AccessLevel.NONE)
private String id;
private String type;
private String name;
#Lob
private byte[] body;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "account_id")
private Account account;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "public_platform_id")
private PublicPlatform publicPlatform;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "service_type_id")
private ServiceType serviceType;
}

You simply do not have an attribute with the name backgroundPicIds in the entity ServiceType.
Try to correct your graph in this way:
#NamedEntityGraph(
name = "serviceType.with.backgroundPicIds",
attributeNodes = #NamedAttributeNode("backgroundPictureId")
)

Related

Spring JPA error org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' [duplicate]

This question already has answers here:
Hibernate throws MultipleBagFetchException - cannot simultaneously fetch multiple bags
(18 answers)
MultipleBagFetchException: cannot simultaneously fetch multiple bags
(1 answer)
Closed 1 year ago.
i have this code
USER:
#Builder
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
#Column(name = "PASSWORD")
private String password;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
private Role role;
#Column(name = "EMAIL")
private String email;
private String country;
private Status status;
#OneToMany(mappedBy = "author",fetch = FetchType.EAGER)
private List<Message> messages;
#OneToMany(mappedBy = "author",fetch = FetchType.EAGER)
private List<Comment> comments;
#OneToOne(optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "GENDER_ID")
private Gender gender;
#OneToOne(optional = false,cascade = CascadeType.ALL)
#JoinColumn(name = "ADDRESS_ID")
private Address address;
#ManyToMany
#JoinTable(
name = "user_subscriptions",
joinColumns = #JoinColumn(name = "CHANNEL_ID") ,
inverseJoinColumns = #JoinColumn(name = "SUBSCRIBER_ID"))
private Set<User> subscribers;
#ManyToMany
#JoinTable(
name = "user_subscriptions",
joinColumns = #JoinColumn(name = "SUBSCRIBER_ID") ,
inverseJoinColumns = #JoinColumn(name = "CHANNEL_ID"))
private Set<User> subscriptions;
}
COMMENT:
#Data
#Entity
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String header;
private String text;
private int likeCount;
#ManyToOne(optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User author;
#ManyToOne(optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "MESSAGE_ID")
private Message message;
}
Country:
#Data
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne(optional = false, mappedBy = "country")
private Address address;
#OneToMany(mappedBy = "country",fetch = FetchType.EAGER)
private List<City> cities;
#OneToMany(mappedBy = "country",fetch = FetchType.EAGER)
private List<Region> regions;
private String description;
}
REGION:
#Data
#Entity
public class Region {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne(optional = false, mappedBy = "region")
private Address address;
#ManyToOne(optional = false,cascade = CascadeType.ALL)
#JoinColumn(name = "COUNTRY_ID")
private Country country;
}
And i have the following problems ,how to solve this?
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.project.webstation.Models.Domain.Country.regions, com.project.webstation.Models.Domain.User.comments]

Subgraphs in hibernate

I have 4 classes: Country, Prefecture, District and Cities, I have a requirement that whenever I persist a Country, that object generates all the necessary relationships with it.
Here is the code for the objects:
#Entity
#Table(name = "countries")
#Getter
#Setter
#AllArgsConstructor
#NamedEntityGraph(name = "graph.prefectures", attributeNodes = #NamedAttributeNode(value = "prefectures"))
#NamedEntityGraph(
name = "graph.CountryPrefectureDistrictCities",
attributeNodes = #NamedAttributeNode(value = "prefectures", subgraph = "subgraph.prefectures"),
subgraphs = {
#NamedSubgraph(name = "subgraph.prefectures",
attributeNodes = #NamedAttributeNode(value = "district", subgraph = "subgraph.district")),
#NamedSubgraph(name = "subgraph.district",
attributeNodes = #NamedAttributeNode(value = "cities"))
})
public class Country implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long countryID;
#Column(name = "CountryName")
private String countryName;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH, mappedBy = "country", orphanRemoval = true)
private Set<Prefectures> prefectures = new HashSet();
public Country() {
}
}
#Entity
#Table(name = "prefectures")
#Getter
#Setter
#AllArgsConstructor
public class Prefectures implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long prefectureID;
#Column(name = "PrefectureName")
private String prefectureName;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH, mappedBy = "prefectures", orphanRemoval = true)
private Set<District> district = new HashSet();
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "countryID", updatable = false, nullable = false)
#JsonIgnore
private Country country;
public Prefectures() {
}
}
#Entity
#Table(name = "district")
#Getter
#Setter
#AllArgsConstructor
public class District implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonProperty("districtID")
private Long districtID;
#Column(name = "DistrictDescription")
#JsonProperty("districtDescription")
private String districtDescription;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH, mappedBy = "district", orphanRemoval = true)
#JsonProperty("cities")
private Set<City> cities = new HashSet();
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PrefectureID", updatable = false, nullable = false)
#JsonIgnore
private Prefectures prefectures;
public District() {
}
}
#Entity
#Table(name = "city")
#Getter
#Setter
#AllArgsConstructor
public class City implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long cityID;
#Column(name = "CityDescription")
private String cityDescription;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DistrictID", updatable = false, nullable = false)
#JsonIgnore
private District district;
public City() {
}
And this is the repository
#Repository
public interface CountryRepository extends JpaRepository<Country, Long>{
#EntityGraph(value = "graph.CountryPrefectureDistrictCities", type = EntityGraph.EntityGraphType.LOAD)
Optional<Country> findById(Long id);
}
My problem is that it doesn't recognize the attribute cities in the subquery of the Country's #NamedEntityGraph
subgraph
Queries
The NamedAttributeNode value of cities is being recognized.
The entity classes are in the same package, and I declared org.springframework.boot:spring-boot-starter-data-jpa:2.5.5 as a dependency which transitively brings in org.hibernate:hibernate-core:5.4.32.Final

Hibernate AttributeOverride annotation error

I have following entities:
public class MyEntity extends AuditableEntity {
#Column
private String name;
}
AuditableEntity class:
public class AuditableEntity {
#Id
#GenericGenerator(name = "uuid-gen", strategy = "uuid2")
#GeneratedValue(generator = "uuid-gen", strategy = GenerationType.IDENTITY)
private String id;
#CreatedBy
#JsonIgnore
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "user", column = #Column(name = "created_by_id")),
#AttributeOverride(name = "clientId", column = #Column(name = "created_by_client_id"))
})
private AuditorDetails createdBy;
#LastModifiedBy
#JsonIgnore
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "user", column = #Column(name = "last_modified_by_id")),
#AttributeOverride(name = "clientId", column = #Column(name = "last_modified_by_client_id"))
})
private AuditorDetails lastModifiedBy;
}
And my AuditorDetails class:
#Embeddable
public class AuditorDetails {
#Column(name = "auditor_client_id")
private String clientId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
private User user;
}
Also, I have AuditorAware that returns AuditorDetails object. When I try to run this, I have following exception:
org.hibernate.MappingException: Repeated column in mapping for entity:
com.aaa.MyEntity column: user_id (should be mapped with insert="false"
update="false")
But I can't make this column(s) not updatable and not insertable. The main goal is to have in MyEntity 4 columns - created_by_id, created_by_client_id, last_modified_by_id, last_modified_by_client_id that will contain all data about row modification and creation. How to fix this exception?
I have fixed this issue just adding annotations AssociationOverrides:
#CreatedBy
#JsonIgnore
#Embedded
#AssociationOverrides({
#AssociationOverride(name = "user", joinColumns = #JoinColumn(name = "created_by_id"))
})
#AttributeOverrides({
#AttributeOverride(name = "user", column = #Column(name = "created_by_id")),
#AttributeOverride(name = "clientId", column = #Column(name = "created_by_client_id"))
})
private AuditorDetails createdBy;
#LastModifiedBy
#JsonIgnore
#Embedded
#AssociationOverrides({
#AssociationOverride(name = "user", joinColumns = #JoinColumn(name = "last_modified_by_id"))
})
#AttributeOverrides({
#AttributeOverride(name = "user", column = #Column(name = "last_modified_by_id")),
#AttributeOverride(name = "clientId", column = #Column(name = "last_modified_by_client_id"))
})
private AuditorDetails lastModifiedBy;

JPA: Use a multiple One-to-many relationships with composite keys

I have these entities:
Run entity:
#Entity
#Table(name = "run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "runId")
public class Run implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "run_id")
private Long runId;
#Column(name = "status")
private Integer status;
#Column(name = "create_date")
private Date date;
#Column(name = "config_id")
private Long configId;
#Column(name = "stream_id")
private Long streamId;
#OneToOne(mappedBy = "run", cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "run_id", unique = true, nullable = true, insertable = true, updatable = true)
private StreamRun streamRun;
...
}
and StreamRun entity:
#Entity
#Table(name = "stream_run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "streamId")
public class StreamRun implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private Long streamId;
#Column(name = "run_id", insertable = false, updatable = false)
private Long runId;
#Column(name = "stream_name")
private String streamName;
#OneToOne
#JoinColumn(name = "run_id")
private Run run;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "stream", orphanRemoval = true, targetEntity = JobRun.class)
private List<JobRun> jobs = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "streamRun", orphanRemoval = true, targetEntity = StreamEvent.class)
private List<StreamEvent> events = new ArrayList<>();
....
}
and JobRun entity:
#Entity
#Table(name = "jobs_run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
#IdClass(JobRunKey.class)
public class JobRun implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private Long id;
#Id
#Column(name = "run_id", insertable = false, updatable = false)
private Long runId;
#Column(name = "name")
private String name;
#Column(name = "type")
private String jobType;
#Column(name = "script")
private String script;
#Column(name = "status")
private Integer status;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "run_id", referencedColumnName = "run_id"), #JoinColumn(name = "job_stream_id", referencedColumnName = "id") })
private StreamRun stream;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobDependencyRun.class)
public List<JobDependencyRun> dependencies = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobEvent.class)
public List<JobEvent> events = new ArrayList<>();
....
}
And all the columns are defined in the MySQL database, Table job_run have composite key of (id and run_id).
The problem is in JobRun entity:
If I define "run_id" field as #ID then an exception appear (when insert)
Parameter index out of range (8 > number of parameters, which is 7).
If I define it without #ID then an exception appear (when update)
Duplicate entry '4-78' for key 'PRIMARY'
If I remove the whole field definition from entity since it is foreign key then the exception will be:
Unable to find column with logical name run_id
"Although the column exists in the table".
Please, can anyone help me?
Do I do anything wrong in the code?
I have managed to find a solution, by modifying JobRun entity as below, and change\access the value of runId from direct setter and getter method.
#Entity
#Table(name = "jobs_run")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
#IdClass(JobRunKey.class)
public class JobRun implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
private Long id;
#Id
#Column(name = "run_id")
private Long runId;
#Column(name = "job_stream_id")
private Long streamId;
#Column(name = "name")
private String name;
#Column(name = "type")
private String jobType;
#Column(name = "script")
private String script;
#Column(name = "status")
private Integer status;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "run_id", referencedColumnName = "run_id", insertable = false, updatable = false),
#JoinColumn(name = "job_stream_id", referencedColumnName = "id", insertable = false, updatable = false) })
private StreamRun stream;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobDependencyRun.class)
public List<JobDependencyRun> dependencies = new ArrayList<>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "jobRun", orphanRemoval = true, targetEntity = JobEvent.class)
public List<JobEvent> events = new ArrayList<>();
...
}

How to map entities with #EmbeddedId?

Does anyone know how to fix the mapping of entities?
Error is
Caused by: org.hibernate.AnnotationException: Column name ID of
com.test.TableAa not found in JoinColumns.referencedColumnName.
TableAa entity
#Entity
#Table(name = "TABLE_AA")
public class TableAa {
#EmbeddedId
private TableAaPk pk;
#Column(name = "FIRST_NAME")
private String first_name;
#Column(name = "LAST_NAME")
private String last_name;
//#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
//#JoinColumns({
//#JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false),
//#JoinColumn(name = "ACCOUNT_NUMBER", referencedColumnName = "ACCOUNT_NUMBER", insertable = false, updatable = false) })
#OneToMany(mappedBy = "tableAa", cascade = CascadeType.ALL)
private List<TableBb> tableBbList;
}
TableAaPk composite key
#Embeddable
public class TableAaPk implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name="ID")
private String id;
#Column(name="ACCOUNT_NUMBER")
private String accountNumber;
}
TableBb entity
#Entity
#Table(name = "TABLE_BB")
public class TableBb {
#EmbeddedId
private TableBbPk pk;
#Column(name = "FIRST_NAME")
private String first_name;
#Column(name = "LAST_NAME")
private String last_name;
}
TableBbPk composite key
#Embeddable
public class TableBbPk implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name="ID")
private String id;
#Column(name="ACCOUNT_NUMBER")
private String accountNumber;
#Column(name="CODE")
private String code;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false),
#JoinColumn(name = "ACCOUNT_NUMBER", referencedColumnName = "ACCOUNT_NUMBER", insertable = false, updatable = false) })
private TableAa tableAa;
}
In your TAbleAa you should have your OneToMany mapping as follows:
#OneToMany(mappedBy = "pk.tableAa", cascade = CascadeType.ALL)
private List<TableBb> tableBbList;
You reference through the embeddable which name is pk.
I think your problem in this entity
#Entity
#Table(name = "TABLE_BB")
public class TableBb {
#EmbeddedId
private TableBbPk pk;
#Column(name = "FIRST_NAME")
private String first_name;
#Column(name = "LAST_NAME")
private String last_name;
// I think the solution is to add the relation #ManyToOne which mapped by in the other side
#ManyToOne // because u refere to this name (tableAa) in #OneToMany(mappedBy = "tableAa"...) in TableAa entity
private TableAa tableAa;
}

Categories