Troubles with Bidirectional One-To-One JPA - spring

I'm coding a CRUD JPA web application. My goal is that a given parent Vehicle can only have a single child Driver, but during runtime this same Driver can instead be assigned to another Vehicle and vice versa. To my understanding, this could be accomplished via an OneToOne relationship.
I've tried some different approaches, but to no success. I can assign a Vehicle to a Driver just fine, but when I try to update/create a new Vehicle and give him a Driver, via controllers, nothing happens. I can only do it the other way around. I'm assuming this is because Vehicle is the parent and I can only create a new relation by updating a parent.
My question is, is it possible to make these updates bidirectional and how can I achieve that?
I've tried using a shared primary key, using a foreign key, using a join table. The result is always the same and I can't quite grasp why. I have an OneToMany relationship working on this application and it works as I expect it to work. I can update on one side or the other, delete on one side or the other. Both entities have been updated. OneToOne? Parent seems to have all the power.
This is what I'm working with right now:
Driver
#Entity
#Table(name= "drivers")
public class Driver {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private int age;
#OneToOne(mappedBy = "driver")
private Vehicle vehicle;
Vehicle
#Entity
#Table(name= "vehicles")
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String make;
#Column(nullable = false)
private String model;
#Column(nullable = false)
private int mileage;
#Column(nullable = false)
private int year;
#Column(nullable = false)
private int fuel;
#OneToOne
#JoinColumn(name = "driver_id")
private Driver driver;
And just for reference, this is the OneToMany relationship I have and that I'm happy with. I'd like my OneToOne to have the same behavior, except I don't need to save a list of entities, only one.
#Entity
#Table(name="stops")
public class Stop {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
#ManyToOne
#JoinColumn(name="route_id")
private Route route;
#Entity
#Table(name="routes")
public class Route {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
#OneToMany
#JoinColumn(name = "route_id")
private List<Stop> stops = new ArrayList<>();
Any tips would be appreciated, thank you for your time.

Related

Spring Boot JPA - OneToMany relationship and database structure

I wonder what database structure would be the best option in my case:
I have entity Questionnaire:
#Table(name = "questionnaire")
public class Questionnaire extends BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy = "fieldStatus")
private List<QuestionnaireField > fieldStatusList;
}
#Table(name = "questionnaire_field")
public class QuestionnaireField extends BaseEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "questionnaire_id")
private Long questionnaireId;
#Column(name = "field_id")
private Long fieldId; //this is id related to the other table Field
#Column(name = "completed")
private boolean completed; //because I need some additional informations like completed I think I can't use ManyToMany between Questionnaire and Field
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
#JoinColumn(name = "questionnaire_id")
private Questionnaire questionnaire;
As you see each Questionnaire can have multiple QuestionnaireFields, BUT each QuestionnaireField is of type Field (hence I added private Long fieldId). Table Field can have 10.000 different fields.
Summary:
one questionnaire can have e.g. 10 Fields, the second one 20 another Fields etc. To store fields related to some particular Questionnaire I created QuestionnaireField table with 2 columns: private Long questionnaireId; and private Long fieldId; . The question is if it is a good approach? That are plain columns not related to any Foreign Key... I try to find the best solution to save Questionnaire with related QuestionnaireFields that are a subset of a big Field table...

JPA one to many, fetch children with specific column value

I have two entities in one to many relationship in my spring-data-jpa project.
Parent entity -
#Entity
#Table(name = "code_group")
public class CodeGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#NaturalId
#Column(nullable = false)
private String entityId;
#OneToMany
#JoinColumn(name = "codeGroupId", referencedColumnName = "entityId")
private List<SystemCode> systemCodes;
// .. getters setters
}
Child entity -
#Entity
#Table(name = "system_code")
public class SystemCode implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(nullable = false)
private String codeGroupId;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
private ActiveOrInactive status;
// getters and setters
}
status column is of enum type, it can only have Active or Inactive value.
My existing code works fine. It is fetching code group with associated system codes. I want to filter system code with status='Active'. How to do this?
Try like this:
#OneToMany
#JoinColumn(name = "codeGroupId", referencedColumnName = "entityId")
#Where(clause = "status= 'Active'")
private List<SystemCode> systemCodes;
You can create such methods in your repo:
List<CodeGroup> getAllBySystemCodes_Status(ActiveOrInactive status);
default List<CodeGroup> getAllActive() {
return getAllBySystemCodes_Status(ActiveOrInactive.Active);
}
default List<CodeGroup> getAllInactive() {
return getAllBySystemCodes_Status(ActiveOrInactive.Inactive);
}

FindBy and OrderBy doesn't order accordingly - Spring Data Jpa

I am using this method :
List<Client>findTop10ByGenderOrderBySurvey_Results_ScoreDesc(char gender);
The logic is this :
I have a Client Model, with a reference OneToMany to the Survey Model, and the Survey Model has a reference of OneToOne with the Results model which has the score field.
So one Client can have many surveys each of which has a score.
I wanted to order the Clients By their score, in descending order, and then get top10 Male Clients with highest score.
The method I'm using does filter By Gender, and returns 10 Clients.
But it returns the same Client more than once,because it has several surveys. And not in an ordered manner.
What am I doing wrong and how do I fix this ?
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "client_id")
private Long id;
#Column(name = "gender")
private char gender;
#OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
#JsonManagedReference
private List<Survey> survey= new ArrayList<Survey>();
}
public class Survey{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SURVEY_ID")
private Long Id;
#ManyToOne
#JsonBackReference
#JoinColumn(name = "client_id")
public Client client;
#OneToOne(cascade=CascadeType.ALL)
#JsonManagedReference
#JoinColumn(name = "surveyresult_id")
private Results surveyResults;
}
public class Results {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SURVEYRESULT_ID")
private Long Id;
private Double score;
}
To filter out duplicate results, use the distinct keyword:
List<Client> findDistinctTop10ByGenderOrderBySurvey_Results_ScoreDesc(char gender);
The OrderBy syntax is incorrect. To order by multiple properties, simply append them like this:
List<Client> findDistinctTop10ByGenderOrderBySurveyDescResultsDescScoreDesc(char gender);
Note: When method names become very long, it is a sign the query might be too complex to be a derived query. It is then recommended to use #Query with a shorter, higher-level method name to describe the query.

#ManyToMany with extra column - how to load via Spring Data?

I have many to many relation between User and Event. I need to have extra column in relational table. I did id:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToMany(mappedBy="user")
private Set<EventUser> eventUsers = new HashSet<>();
//
}
#Entity
public class Event {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private long id;
#OneToMany(mappedBy="event")
private Set<EventUser> eventUsers = new HashSet<>();
//
}
#Entity
#Table(name = "Event_User")
public class EventUser {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private long id;
private String reaction;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "event_id")
private Event event;
//
}
But now... I don't know how to load all events where user has concrete email. Before it I used method:
findByUsersEmail(String email);
Now I can't do this, because Event doesn't have Set users field.
Any ideas ?
What you need here is property-expressions.
Just a quick idea to start:
findByEventUsers_UserEmail(String email);
Note: Dont forget that creating queries by method names is a very limited approach and only used by trivial cases. In any other case, don't be afraid of using the #Query annotation on the method or write JPQL/Criteria API manually.

How to make one Model for similar tables?

I have several similar tables in DB.
Now I use for each table own Model and Repository
But I think, this is not right decision.
Can I make a one Model and Repository for all similar tables?
#Entity
#Table(name = "BEDROOM", schema = "public")
public class BedroomModel extends AllFinishProductModel{
#Column(name = "PHOTO")
private String photo;
#Id
#Column(name = "ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "STRUCTURE") //organza, curtain ....
private String structure;
#Column(name = "PAINT") //abstraction, geometric ....
private String paint;
#Column(name = "HEIGHT")
private String height;
#Column(name = "COLOR")
private String color;
#Column(name = "QUANTITY")
private Double quantity;
#Column(name = "PRICE")
private BigDecimal price;
#Column(name = "SEWED")
private String itIsSewed;
... getters and setters
}
I have a similar tables: CABINET, GUESTROOM, CHILDREN_ROOM, KITCHEN, CURTAIN and TULLE.
Which code should be used for repository?
I tried to find answers to the questions inhttps://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
But I don't find answers here.
Can you give advice, how to make it or link?
You can use entity inheritance with #MappedSuperclass annotation on parent class to get common properties in child classes/tables.
So, for example you have a parent Room entity with common properties, which you annotate with #MappedSuperclass.
#MappedSuperclass
public class Room {
#Column
private String name;
#Column(name = "DESCRIPTION")
private String description;
// some more common properties
}
And concrete rooms, e.g.:
#Entity
public class Bedroom extends Room
{
// common properties will be inherited
private Bed bed;
private NightLamp nightLamp;
}
Now, the important part is that Room is not mapped as any table. The room is a "virtual" table, which doesn't exist in the db. Only concrete entities exist as tables, like Bedroom.
Here you have the link to the official javadoc:
http://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html

Resources