I have a problem with OneToMany annotation
#Entity
#Table(name = "RESULT_HISTORY")
public class ResultHistoryImpl implements ResultHistory, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany
private final Set<Game> games = new HashSet<>();
...
}
and class
#Entity
#Table(name = "GAME")
public class GameImpl implements Game, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
...
}
I have more fields, setters/getters and constructors
I use spring and in my configuration files I have packagesToScan where I put packages of those classes
The problem is that I get org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class
I read many topics on stackoverflow, so the problem isn't using org.hibernate.annotation etc
What you tried is not possible. Game is an interface and you cannot map an interface to DB, because hibernate does not know which implementation to use. But what you can do, is
use in all your entity classes the GameImpl class directly. I mean correct your ResultHistoryImpl class to this: #OneToMany private final Set<GameImpl> games = new HashSet<GameImpl>();
If you want to have another abstraction, add an abstract class AbstractGame implements Game and annotate it with #Entity and use it instead of the Game interface.
Use #MappedSuperclass annotation on Game.
For #OneToMany you have to provide a mappedBy property which points to a field name in the other class. In your case:
public class ResultHistoryImpl {
...
#OneToMany(mappedBy = "resultHistory")
private final Set<GameImpl> games = new HashSet<>();
}
public class GameImpl {
#ManyToOne
#JoinColumn(name = "result_history")
private ResultHistoryImpl resultHistory;
}
Related
I am using Spring Boot and Jackson and Hibernate to create an API. Hibernate connects to a MySQL database.
I understand the good practices but I'm stuck on a particular point.
I have an n:m relationship that contains an extra field.
Ex: Author(id, ...) -> Written(idAuthor, idBook, date) <- Book(id, ...)
I understand how to map a traditional n:m relationship, but this technique does not apply to me this time.
For this, I found a source on the internet that showed the solution: create an intermediate class in my code that contains an Author type object and a Book type object + my additional fields.
#Entity
#Table(name = "Author")
public class Author implements Serializable {
/...
#Id
#GeneratedValue
private int id;
#OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
private Set<Written> written= new HashSet<>();
/...
}
#Entity
#Table(name = "Book")
public class Book implements Serializable{
/...
#Id
#GeneratedValue
private int id;
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
private Set<Written> written= new HashSet<>();
/...
}
public class Written implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "idAuthor")
private Author author;
#Id
#ManyToOne
#JoinColumn(name = "idBook")
private Book book;
//Extra fields ....
}
That's a bidirectional link.
With this code, I get an infinite recursivity error:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.exampleAPI.api.model.Book["written"])]
I tried to use #JsonIgnore, #JsonManagedReference and #JsonBackReference on the Written class, also tried to use transient keyword, but nothing worked.
I can't find any source on the internet that could help me, and neither can the documentation for this particular case.
Can someone help me?
When unhandled bidirectional relationship occurs, Jackson faces infinite recursion.
I tried to use #JsonIgnore, #JsonManagedReference and #JsonBackReference on the Written class
You need to use #JsonManagedReference and #JsonBackReference annotations separately to prevent these cycles between Book and Written. A side note, transient has nothing to do with the persistence but the serialization. JPA works with the #Transient annotation.
public class Book implements Serializable {
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
#JsonBackReference
private Set<Written> written= new HashSet<>();
...
}
public class Written implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "idBook")
#JsonManagedReference
private Book book;
...
}
Important: Don't send database entities through REST (probably what you are up to do). Better create a DAO object without bidirectional relationship and map entities into DAOs. There are several libraries able to do that: I highly recommend MapStruct, however ModelMapper is also an option. If there is a lower number of such entities, using constructors/getters/setters would be enough.
I have an #Entity class, with an #Id annotation and a #OneToOne annotation on the same field. Usually this would not be a problem, but the entity class of the field with these annotations uses a composite key. This is causing more complications than I anticipated.
Here is the entity class that is posing the problem:
#Entity
public class ReportDetails implements Serializable {
#Id
#OneToOne
private MachineLine machineLine;
}
And here is the MachineLine entity class that is being used as an ID in ReportDetails:
#Entity
#IdClass(MachineLine.MachineLineKey.class)
public class MachineLine {
#Id
#ManyToOne
private Machine machine;
#Id
private long lineIndex;
public static class MachineLineKey implements Serializable {
private Machine machine;
private long lineIndex;
}
}
I have left out any extra fields and the getters and setters from these class definitions, to save space.
When I try to run my application it gives the following exception:
java.lang.IllegalArgumentException: This class [class ReportDetails] does not define an IdClass
When I put an #IdClass annotation on ReportDetails it then requires defining the individual fields of whatever class I define in #IdClass, like in MachineLine. However, I am trying to avoid doing this, in favour of having the whole MachineLine entity returned whenever a ReportDetails entity is retrieved from the database.
Is there a way of having MachineLine as the ID field of ReportDetails, without having to define extra fields within ReportDetails?
This is what JPA calls a "derived identity". You might try something like this:
ReportDetails:
#Entity
public class ReportDetails implements Serializable {
// all attributes map by the relationship: AttributeOverride is not allowed
#EmbeddedId
private MachineLine.Id id;
#MapsId
#JoinColumns({
#JoinColumn(name="machineId", referencedColumnName="machineId"),
#JoinColumn(name="machineLineIndex", referencedColumnName="index")
})
#OneToOne
private MachineLine machineLine;
// ...
}
MachineLine:
#Entity
public class MachineLine {
#EmbeddedId
private Id id;
#MapsId("machineId") // maps machineId attribute of embedded id
#ManyToOne
private Machine machine;
// ...
#Embeddable
public static class Id implements Serializable {
private long machineId; // corresponds to PK type of Machine
private long index;
// ...
}
}
Machine:
#Entity
public class Machine {
#Id
private long id;
#OneToMany(mappedBy = "machine")
private List<MachineLine> lines;
// ...
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
I saw similar questions, but answers weren't helpful. So, i get this error:
Use of #OneToMany or #ManyToMany targeting an unmapped class: com.podro.model.Journey.roadWay[com.podro.model.RoadElement]
I'm trying to create List with objects of RoadElements (which is interface for class Point and Section). There is any other way to do it? From what i know, i guess that is the only way to create proper mapping for this classes, and have list of this elements.
#Entity
#Table(name="Journey")
public class Journey {
// Some other fields
#Column(name="road_way")
#ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<RoadElement> roadWay;
}
#MappedSuperclass
public interface RoadElement {}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name="Point")
public class Point implements RoadElement{
#Id
#Column(name="id")
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
private String name;
#Column(name="time_in_days")
private int timeInDays;
private Rate rating;
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name="Section")
public class Section implements RoadElement{
#Id
#Column(name="id")
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name="section_name" , length=100)
private String sectionName;
#Column(name="time_in_days")
private int timeInDays;
#Column(name="kind_of_transport")
private Locomotion kindOfTransport;
}
Thanks for answers, I would be very grateful for help!
Associations are between entities. RoadElement is not an entity. It's an interface.
You may not do what you're trying to do. Hibernate needs to know the type of the entities contained in roadWay.
So, RoadElement should be a class, annotated with #Entity, having an ID that uniquely identifies a RoadElement among all the road elements (sections, points, etc.)
Section and Point should extend from RoadElement, and should NOT have their own ID, since it's inherited from RoadElement.
I have two entities, let's say
Person.java:
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#OneToMany(mappedBy = "personData", cascade = CascadeType.PERSIST)
private List<SkillsData> skillsData;
// ...
}
SkillsData.java
#Entity
#Table(name = "SkillsData")
public class SkillsData implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#JoinColumn(name = "PERSONID")
#ManyToOne(cascade = REMOVE)
private Person personData;
// ...
}
When I create a person, add a list of type SkillsData to it's skillsData field and persist it everything works with no exceptions thrown, but when I browse the database directly in the SkillsData table the field PERSONID is not populated and because of that the skills added can't be referenced to the right person.
I'm trying to fix this problem for quite some time and I'll be thankful for any help.
The problem might be in the fact that you're not setting SkillsData.personData before persisting leaving it null.
You must set it cause adding SkillsData to the Person.skillsData list is not enough since you declared this side of relationship as inverse(mappedBy attribute).
Therefore it is the SkillsData.personData non-inverse side who is responsible for establishing this relationship.
I have searched and found similar issues, but they don't quite seem to be the same problem as
Why am I getting this NullPointer exception?
OneToOne Mapping with hibernate/JBoss/Seam
ANN-613 - NPE when mappedBy property is wrong on a #OneToOne
ANN-558 - #OneToMany(mappedBy="") can not recognize properties in parent classes
Hibernate Users - NPE with #Id on #OneToOne
I have a few entities mapped like this:
Person
|
+--User
I want to add a new entity PersonPartDeux with a OneToOne mapping to Person. The resulting mapping should look something like this:
Person + PersonPartDeux
|
+--User
When I do so, a NullPointerException is thrown while trying to load the mapping:
java.lang.NullPointerException
at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:135)
How do I specify the mapping so I can avoid this exception?
Here's my code:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Person implements Serializable
{
#Id
#GeneratedValue
public Long id;
#Version
public int version = 0;
public String name;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
public PersonPartDeux personPartDeux;
}
#Entity
public class PersonPartDeux implements Serializable
{
#Id
#GeneratedValue(generator = "person-primarykey")
#GenericGenerator(
name = "person-primarykey",
strategy = "foreign",
parameters = #Parameter(name = "property", value = "person")
)
public Long id = null;
#Version
public int version = 0;
#OneToOne(optional=false, mappedBy="person")
public Person person;
public String someText;
}
#Entity
#PrimaryKeyJoinColumn(name = "person_Id")
public class User extends Person
{
public String username;
public String password;
}
As for why I'm bothering, I need both the inheritance and the OneToOne mapping to solve different known issues in my application.
Attach the Hibernate source to your project, so you can click thru or 'Open Type' (Ctrl-Shift-T in Eclipse) to view the OneToOneSecondPass source.
Seeing the source, will give you a clear indication as to what needs to be specified.
In my source (Hibernate 4.1.7), line 135 is
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
However you're probably using an earlier version.
Looking at the mappings, I'm suspicious of the #OneToOne definition -- mappedBy="person".
#OneToOne(optional=false, mappedBy="person")
public Person person;
What does it usefully mean, to map an association property by itself? Hibernate already knows the property is a OneToOne -- you just told it that.
Pointing the underpinning mapping/ FK of the property, at itself.. probably isn't actually telling Hibernate any correct or useful information.
Here's an example from the HB dosc, perhaps showing better how to do what you want:
#Entity
class MedicalHistory implements Serializable {
#Id Integer id;
#MapsId #OneToOne
#JoinColumn(name = "patient_id")
Person patient;
}
#Entity
class Person {
#Id #GeneratedValue Integer id;
}
Source: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
(3.5 docs off JBoss site.)
Cheers, hope this helps.