I use spring data jpa and i try to do a many to many unidirectional relation.
#Entity
public class Appartment {
...
#ManyToMany
private List<AppartmentFeatureOption> featureOption;
}
#Entity
public class AppartmentFeatureOption {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long appartmentFeatureOptionId;
private String name;
private BigDecimal value;
}
My database is created at run time, but i get this error
org.hibernate.DuplicateMappingException: Same physical table name [appartment_feature_option] references several logical table names: [AppartmentFeatureOption], [Appartment_AppartmentFeatureOption]
Any idea?
Edit with this code that work
#ManyToMany
#JoinTable(name="appartment_feautre_option_appartment", joinColumns=#JoinColumn(name="appartment_id"), inverseJoinColumns=#JoinColumn(name="appartment_feautre_option_id"))
private List<AppartmentFeatureOption> featureOption;
Is this is actually your real code, maybe the issue is that you are using a ManyToMany relationship between Appartment and AppartmentFeatureOption whereas there is no link to Appartment in the AppartmentFeatureOption.
From my understanding for one Appartment you want to have several AppartmentFeatureOption, which is a OneToMany relationship.
Related
I am trying to implement the OneToOne association in JPA and trying to join two tables using spring boot and spring data JPA. I created one spring boot microservice and implemented the one to one association in my model. But when I am running code I am getting the following error ,
Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElement
Here My First model class Users.java is like following,
#Entity
#Table(name = "users")
public class Users implements Serializable {
private static final long serialVersionUID = 9178661439383356177L;
#Id
#Column(name="user_id")
public Integer userId;
#Column(name="username")
public String username;
#Column(name="password")
public String password;
}
And I am testing association by controller using following code,
#GetMapping("/load")
public Users load() {
return (Users) userObj.findAll();
}
Can anyone help to resolve this association issue please ?
This is wrong.
#OneToOne(mappedBy="nuserId")
public Set<UserRoleMapping> roleUserRoleMappingMappingJoin;
}
OneToOne means only one object..right?
See this for mappings understandings.
https://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/collections.html#collections-persistent
Annotation #OneToOne defines a single-valued association to another entity, and in your case you associate a user to a Set of UserRoleMapping instead of associating it with a single object of that class. Use #ManyToOne annotation
Actually the exception refers to an invalid #OneToMany, #ManyToMany or #CollectionOfElement mapping
and this can only be
#OneToMany()
#JoinColumn(name="nuser_id" , referencedColumnName="nuserId")
public Users nuserId;
If the #OneToMany relation is valid change this at first to
#OneToMany()
#JoinColumn(name="nuser_id" , referencedColumnName="nuserId")
public List<Users> users;
If the #OneToMany relation is NOT valid change this to
#OneToOne()
#JoinColumn(name="nuser_id" , referencedColumnName="nuserId")
public Users users;
I have an application that teaches the user how to play various card games. The data model that gets persisted consists of a TrainingSession with a uni-directional one-to-many relationship with the Hands.
[EDIT] To clarify, a Hand has no existence outside the context of a TrainingSession (i.e they are created/destroyed when the TrainingSession is). Following the principals of Data Driven Design, the TrainingSession is treated as an aggregate root and therefore a single spring-data CrudRepository is used (i.e., no repository is created for Hand)
When I try to save a TrainingSession using a CrudRepository, I get: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (blackjack.hand, CONSTRAINT FKrpuxac6b80xc7rc98vt1euc3n FOREIGN KEY (id) REFERENCES training_session (tsid))
My problem is the 'save(trainingSession)' operation via the CrudRepository instance. What I don't understand is why the error message states that FOREIGN KEY (id) REFERENCES training_session (tsid)). That seems to be the cause of the problem but I cant figure out why this is the case or how to fix it. The relationship is uni-directional and nothing in the Hand class refers to the TrainingSession.
The code, minus all the getters and setters, is:
#Entity
public class TrainingSession {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer tsid;
private String strategy;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="id")
private List<Hand> hands;
private int userId;
protected TrainingSession() {
}
public TrainingSession(int userId, Strategy strategy, List<Hand> hands) {
this.strategy = strategy.getClass().getSimpleName();
this.hands = hands;
this.userId = userId;
}
while Hand is
#Entity // This tells Hibernate to make a table out of this class
public class Hand {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int p1;
private String p1s;
private int p2;
private String p2s;
private int d1;
private String d1s;
private int trials;
private int score;
public Hand() {
}
You need to save your TrainingSession and Hand objects first before saving the adding the hand objects to TrainingSession.
TrainingSession ts1 = new TrainingSession();
trainingSessionManager.save(ts1);
Hand hand1 = new Hand();
handManager.save(hand1);
Hand hand2 = new Hand();
handManager.save(hand2);
ts1.gethands().add(hand1);
ts1.gethands().add(hand2)
trainingSessionManager.save(ts1);
If you check your database you will find 3 tables TrainingSession, Hand and TrainingSession_Hand, The TrainingSession_Hand table references to both TrainingSession and Hand both. Therefore you need to save TrainingSession and hand before saving the relationship.
Found the problem. I was assuming that when spring-data set up the DB tables, it was able to figure out and set up the uni-directional 1-to-many relationship. Apparently that isn't the case. When I configure the relationship as bi-directional everything seems to work.
To fix things I:
removed from TrainingSession the #joincolumn annotation for hands
in Hands I added a TrainingSession field with a #ManyToOne annotation:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "tsid", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private TrainingSession tsession;
I also added in the Hand class the getter/setter for tsession
I can now do a save of the entire aggregate construct using only a TrainingSessionRepository.
I am planning to store data from multiple tables which has one to many JPA relationship. I am creating my Repository interface which extends from JPARepository. My question is If I want to save a data on Many sides of relationship (in the below scenario it's Tour) then shall I do with TourRepository or PersonRespository?
On a similar note Is it ideal to create individual repository classes for every JPA entities where data need to be stored? or any better way with limited repository classes the data store to database can be achieved?
#Entity
#Table(name="Person")
public class Person implements Serializable{
...
...
#OneToMany(mappedBy = "person")
private List<Tour> tours;
...
#Entity
#Table(name = "Tour")
public class Tour implements Serializable{
...
...
#ManyToOne
#JoinColumn(name = "PERSON_ID")
private Person person;
...
You have two independent entities. Person can exist without Tour and Tour can exist without Person. So you should have two repositories - for Person and Tour to store their data independently:
Tour tour1 = new Tour("tour1");
tourRepo.save(tour1);
Person person1 = new Person("person1");
person1.addTour(tour1);
personRepo.save(person1);
You chose the bidirectional one-to-many association so you have to use a 'helper' method like addTour to link both entities:
public Person addTour(Tour tour) {
tour.setPerson(this);
this.tours.add(tour);
return this;
}
Additional info: Best Practices for Many-To-One and One-To-Many Association Mappings
Add cascade to tours:
#OneToMany(mappedBy = "person", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Tour> tours;
When you save person object, his tours will be saved automatically.
By the way, in Person class, you should have an addTour(...) utilities method like this:
// Person.java
public void addTour(Tour tour){
this.tours.add(tour);
tour.setPerson(this);
}
I would suggest you to use CascadeType.ALL on #OneToMany mapping in Person entity:
#OneToMany(mappedBy = "person",cascade = {CascadeType.ALL})
private List<Tour> tours;
And then create repository for person to save person object with the list of tours .
CascadeType.ALL means persistence will propagate all EntityManager operations like PERSIST, REMOVE, REFRESH, MERGE, DETACH to the relating entities.
I'm using Spring Boot JPA with Gradle. I'm struggling to find a guide that I can follow which focusses on creating a relational database with the correct Syntax for Spring Boot. I had a go but I get this error
No property idTestCase found for type TestRun!
I want TestRun and TestData entities with a OneToOne relationship with each other, and a TestCase entity that has a OneToMany relationship with TestRun. I reckon that TestRun should contain the foreign keys for TestData and TestCase.
Many times I make changes and it will not build, and when it does build the tables do not look correct, this is what I created:
#Entity
public class TestRun {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private long testRunId;
private Boolean result;
#OneToOne #JoinColumn(name="testData_id")
private TestData testData;
#ManyToOne #JoinColumn(name="testCase_id")
private TestCase testCase;
}
#Entity
public class TestCase {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private long testCaseId;
private String name;
private String description;
#OneToMany(cascade=CascadeType.ALL, mappedBy="testCase",targetEntity=TestRun.class)
private Collection<TestRun> testRun;
}
#Entity
public class TestData {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private long testDataId;
#OneToOne(cascade=CascadeType.ALL, mappedBy="testData",targetEntity=TestRun.class)
private TestRun testRun;
}
From the guides it isn't clear to me what goes in #JoinColumn(name= some say it needs to link to a field on your POJO and some say it doesn't. If I create the foreign key field in my POJO then I get two foreign key fields in the database table and if I don't it doesn't build at all.
For example from the error I can infer it wants me to add the following fields to TestRun:
private long idTestCase;
private long idTestData;
But then my database appears as:
SELECT * FROM TEST_RUN;
TEST_RUN_ID
ID_TEST_CASE
ID_TEST_DATA
RESULT
TEST_CASE_ID
TEST_DATA_ID
(no rows, 3 ms)
I tried setting #JoinColumn(name= to the name of the primary key field on the other side of the relationship but again it did not build.
Many thanks
I found the guide at JBoss to be the most helpful in describing the different mappings.
I'm using Spring Data JPA and have a many to one relationship from Child to Parent Class using hibernate. I'm writing a search API which would search on child table using some child table columns and return list of child objects along with some data from Parent class for each child object. I'm doing by default eager fetch for many to one relationship. The problem i'm facing is lets say after searching child table 10 entries are returned then hibernate is doing 10 different select queries on parent class to get Parent object for each child object. Is there a way to optimize this ? There is a solution given to similar problem here but it is for one to many case. I could not find anything helpful regarding this on web also. Any ideas ?
as you didn't show any codes in the question, it's a little hard to solve it but I think if you specify join column (#JoinColumn annotation) and use #OneToMany annotation in parent class(with specifying fetch type) and #ManyToOne inside child you should not have any problem:
#Entity(name ="Parent")
public class Parent {
#Id
#Column
private int id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name= "paren_id")
private Set<Child> children;
//getters and setters
}
#Entity(name ="Child")
public class Child{
#Id
#Column
private int id;
#ManyToOne
private Parent parent;
//getters and setters
}