#OneToOne or #OneToMany references an unkown entity - java

I'm having some issues with an error that occurs from time to time on my project. I have some JPA entities in project 1 that are used on project 2.
I'm using micronaut (groovy), liquibase and hibernate.
The error I get is as follows:
2022-03-07 09:44:18.513 xxxxx-xxx-xxx ERROR [xxxxx-xxx,,,] [,,||||,] --- [ main] i.m.c.h.jpa.EntityManagerFactoryBean : Hibernate mapping error
org.hibernate.AnnotationException: #OneToOne or #ManyToOne on root.company.library1.domain.process.actor.ActorCreationProcess.actorType references an unknown entity: root.company.library1.domain.actor.ActorType
The entities are:
#Entity
#Table(name = 'actor_creation_process')
class ActorCreationProcess extends BaseEntity {
#JoinColumn(name = 'actor_type_id')
#ManyToOne(optional = false, targetEntity = ActorType)
ActorType actorType
}
And:
#Entity
#Table(name='actor_type')
class ActorType extends BaseEntity {
#Id
#GeneratedValue
UUID id
#Column (nullable = false)
String name
}
The superclass "BaseEntity" is as follows:
#MappedSuperclass
abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 7933099518124664248L
#Column
LocalDateTime createdAt
#Column
LocalDateTime updatedAt
#PrePersist
void onCreate() {
this.createdAt = LocalDateTime.now()
}
#PreUpdate
void onUpdate() {
this.updatedAt = LocalDateTime.now()
}
}
Sometimes I'll execute it and it won't throw the error.
Any suggestions?
Edit: Specified I'm using Groovy and BaseEntity specification.

please make sure that base entity as the following
#MappedSuperclass
public class BaseEntity {}
Also,
make sure that target entity refer to the mentioned entity from the same package not different package and it must refer to the class not the entity, i mean
#ManyToOne(optional = false, targetEntity = ActorType.class)
ActorType actorType

Related

Mapped subclass is retrieved as superclass by Hibernate

I have a class Project, a superclass Resource with two subclasses StorageResource and ComputeResource. I have defined a Hibernate mapping (I am using Hibernate version 5.3.7.Final) as follows:
#Entity
#Table(name = "PROJECTS", ...})
public class Project implements Serializable {
...
#OneToMany(
mappedBy = "project",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Resource> resources;
...
}
#Entity
#Table(name = "resources")
#Inheritance(strategy = InheritanceType.JOINED)
public class Resource implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#ManyToOne
private Project project;
...
}
#Entity
#Table(name = "storage_resources")
#PrimaryKeyJoinColumn(name = "id")
public class StorageResource extends Resource implements Serializable {
...
}
#Entity
#Table(name = "compute_resources")
#PrimaryKeyJoinColumn(name = "id")
public class ComputeResource extends Resource implements Serializable {
...
}
My Java code can save instances of both subclasses (StorageResource and ComputeResource) correctly to the database. However, when I load these records by loading a project and its resources, I have the following:
Storage resource records are loaded as Java objects that are instances of StorageResource,
Compute resource records are loaded as Java objects that are instances of Resource, not of ComputeResource as I would expect.
I have spent the last two days trying to figure out why this is happening: the mappings of both sub-classes are the same. Am I missing something?
EDIT
I found the problem. It was quite misleading, because there was no error message. The environment in which the bug occurred had an outdated configuration file. The Hibernate mapping for ComputeResource
<mapping class="....ComputeResource"/>
was missing. After adding this line the mapping is working as expected.

Hibernate Envers targetAuditMode = RelationTargetAuditMode.NOT_AUDITED not working

I have the following class:
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
public class Yard extends ModelObject {
// Relations
#ManyToOne(optional=false)
#JoinColumn(name = "house_id", foreignKey=#ForeignKey(name="fk1_yard"))
#Getter #Setter
#JsonView({Views.AdminPortal.class})
private House house = null;
}
And I get the following error
Could not write JSON: Unable to find com.db.model.main.House with id 7
My understanding was that targetAuditMode = RelationTargetAuditMode.NOT_AUDITED would prevent this error by only auditing the id number. What am I doing wrong here?
Your usage is incorrect. I believe what you're looking for is:
#Audited
#Entity
public class Yard extends ModelObject {
#ManyToOne(optional=false)
#JoinColumn(name = "house_id", foreignKey=#ForeignKey(name="fk1_yard"))
#Getter
#Setter
#JsonView({Views.AdminPortal.class})
#Audited(targetAuditMode = RElationTargetAuditMode.NOT_AUDITED)
private House house = null;
}
You'll notice how the #Audited annotation with targetAuditMode is being used on the association in the entity mapping rather than on the class-mapping. That attribute has no impact at the class-level.

#Column and #Enumerated doesn't work in embeded entity

I have main entity:
#Entity
#Table(name = "partners")
public class Partner {
#ElementCollection
#CollectionTable(
name = "external_login",
joinColumns = #JoinColumn(name = "partner_id")
)
private List<ExternalLogin> externalLogins;
...
}
And ExternalLogin is embeded entity
#Embeddable
public class ExternalLogin {
#Column(name = "type")
#Enumerated(value = EnumType.STRING)
private ExternalLoginType type;
#Column(name = "login")
private String login;
#Column(name = "password_value")
private String passwordValue;
}
public enum ExternalLoginType {
ABC;
}
#Column and #Enumerated not works in ExternalLogin entity.
For example in query will be external_login.passwordValue instead of external_login.password_value.
#Enumerated(value = EnumType.STRING) doesn't work too. Hibernate is trying to get int value of filed instead string.
Can anyone help me?
You misuse annotation #Embeddable. See description in oracle docs https://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html
Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entit
#Embeddable annotation makes sense only for singular assotiation fields. Annotating list fields as #Embeddable is wrong.
Just replace
#Embeddable
public class ExternalLogin {
to
#Entity
public class ExternalLogin {
I had exactly the same issue just now.
The solution for me ended up being adding
#Access(FIELD)
To the Embeddable object.

Spring Boot JPA - OneToMany relationship causes infinite loop

I have a two objects with simple #OneToMany relationship which looks as follows:
parent:
#Entity
public class ParentAccount {
#Id
#GeneratedValue
private long id;
private String name;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "parentAccount")
private Set<LinkedAccount> linkedAccounts;
}
child:
#Entity
public class LinkedAccount {
#Id
#GeneratedValue
private long id;
#ManyToOne(optional = false)
private ParentAccount parentAccount;
private String name;
// empty constructor for JPA
public LinkedAccount() {
}
}
I ma using Spring CrudRepository to operate with these entities. However, when calling ParentAccount parent = parentAccountRepository.findOne(id);, some kind of infinite loop starts happening and hibernate spams this all over the console:
Hibernate: select linkedacco0_.parent_account_id as parent_a6_1_0_, linkedacco0_.id as id1_0_0_, linkedacco0_.id as id1_0_1_, linkedacco0_.aws_id as aws_id2_0_1_, linkedacco0_.key_id as key_id3_0_1_, linkedacco0_.name as name4_0_1_, linkedacco0_.parent_account_id as parent_a6_0_1_, linkedacco0_.secret_key as secret_k5_0_1_ from linked_account linkedacco0_ where linkedacco0_.parent_account_id=?
I tried changed the fetch type to LAZY but then I get this error:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.berrycloud.scheduler.model.ParentAccount.linkedAccounts, could not initialize proxy - no Session
(It seems that it is trying to do the lazy load outside of the transactional context).
This is my CRUD repository:
#Repository
public interface ParentAccountRepository extends CrudRepository<ParentAccount, Long> {
}
Could someone tell me how to resolve this issue? I would prefer the solution with EAGER fetch. Thank you for any tips
EDIT: here is the schema I am using
CREATE TABLE parent_account (
id BIGINT auto_increment,
name VARCHAR(80) null,
PRIMARY KEY (`id`)
);
CREATE TABLE linked_account (
id BIGINT auto_increment,
parent_account_id BIGINT,
name VARCHAR(80) null,
FOREIGN KEY (`parent_account_id`) REFERENCES `parent_account` (`id`),
PRIMARY KEY (`id`)
);
As the first answer suggests:
Do not use Lombok's #Data annotation on #Entity classes.
Reason: #Data generates hashcode(), equals() and toString() methods that use the generated getters. Using the getter means of course fetching new data even if the property was marked with FetchType=LAZY.
Somewhere along the way hibernate tries to log the data with toString() and it crashes.
Problem solved. I was using a custom #toString method in the LinkedAccount which was referencing the ParentAccount. I had no idea that this could cause any problem and therefor I did not include the toString in my question.
Apparently, this was causing an infinite loop of lazy loading and removing this reference fixed the problem.
As user1819111 told, #Data from Lombok is not compatible with #Entity and FetchType=LAZY. I had used Lombok.Data (#Data) and I was getting this error.
As I don't want do create all get/set, I just put the Lombok #Setter and #Getter in your class and all will work fine.
#Setter
#Getter
#Entity
#Table(name = "file")
#SequenceGenerator(name = "File_Sequence", allocationSize=1, sequenceName = "file_id_seq")
public class MyClass{
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "File_Sequence")
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "file", cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
private Set<Base2FileDetail> details = new HashSet<>();
}
Something like this does not work?
#Entity
public class Account {
#Id
#GeneratedValue
private long id;
private String name;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="manager_id")
private Account manager;
#OneToMany((fetch = FetchType.EAGER, mappedBy="manager")
private Set<Account> linkedAccounts = new HashSet<Account>();
}
I recently had this issue due to a poorly defined Jackson2HttpMessageConverter.
I had done something like the following.
#Bean
RestTemplate restTemplate(#Qualifier("halJacksonHttpMessageConverter")
TypeConstrainedMappingJackson2HttpMessageConverter halConverter) {
final RestTemplate template = new RestTemplateBuilder().build();
halConverter.setSupportedMediaTypes(List.of(/* some media types */));
final List<HttpMessageConverter<?>> converters = template.getMessageConverters();
converters.add(halConverter);
template.setMessageConverters(converters);
return template;
}
This caused a problem because the media types did not include all the defaults. Changing it to the following fixed the issue for me.
halConverter.setSupportedMediaTypes(
new ImmutableList.Builder<MediaType>()
.addAll(halConverter.getSupportedMediaTypes())
.add(/* my custom media type */)
.build()
);
This simple way worked for me. Just use JsonIgnoreProperties .
#JsonIgnoreProperties(value = {"linkedAccounts"})
#ManyToOne(cascade = { CascadeType.PERSIST})
#JoinColumn(name = "abc", referencedColumnName = "abc")
private ParentAccount parentAccount;
This way worked for me without removing #ToSring annotation:
#Entity
#Getter
#Setter
#ToString
#RequiredArgsConstructor
#AllArgsConstructor
#Table(name = "parent_accounts")
public class ParentAccount {
#JsonIgnoreProperties({"parentAccount"})
#OneToMany(mappedBy = "parentAccount",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<LinkedAccount> linkedAcounts;
// ...
}
#Entity
#Getter
#Setter
#ToString
#RequiredArgsConstructor
#AllArgsConstructor
#Table(name = "linked_accounts")
public class LinkedAccount {
#JsonIgnoreProperties("linkedAcounts")
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parentAccount_id")
private ParentAccount parentAccount;
// ...
}
PS: In #JsonIgnoreProperties You can also ignore more than one field for preventing infinite loop

Hibernate. Repeated column when mapping #IdClass annotated entity with composite key

I've ran into problem with composite primary key handling by Hibernate as a JPA provider.
My entities look like below
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
Looks pretty simple yet no matter what I do I keep getting the following exception (lines are splitted for readability):
org.hibernate.MappingException:
Repeated column in mapping for entity: ExternalMatch
column: external_object_id (should be mapped with insert="false" update="false")
I've tried placing annotation on entity class fields and key class fields together as well as separately, moving all annotations from fields to getters on each one of the classes, using key calss as #Embeddable and putting it into the entity class with #EmbeddedId. Nothing seems to work.
This case seems trivial so maybe it's something wrong with our setup but I can't even imagine where to look for the issue.
Any advice is much appreciated.
It appears that I shot myself in the foot with this.
The issue was that I had a biderectional mapping between ExternalMatch and ExternalObject I forgot about trying to replace the actual entity with its integer id.
So changing
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "external_object_id", nullable = false)
private List<ExternalMatch> matches;
// ...
}
to reprsent actual mappings like this
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#ManyToOne
#JoinColumn(name = "external_object_id", referencedColumnName = "id")
private ExternalObject externalObject;
#Id
#ManyToOne
#JoinColumn(name = "place_id")
private Poi place;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Poi place;
private ExternalObject externalObject;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "externalObject")
private List<ExternalMatch> matches;
// ...
}
resolved the repeated mapping issue yet leaving us with all the familiar troubles a biderectional mapping creates :)

Categories

Resources