What #Json annotation to use for forgein key - spring-boot

I need an annotation that will only return certain Object properties or only forgein key
User:
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
...
#JsonIgnore
#OneToMany(mappedBy="user")
private Set<Log> logs=new HashSet<>();
Logs:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long logsId;
...
#JsonProperty<--------
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
...
I am using #JsonProperty but it returns a whole object with vulnerable data

You can use #jsonignore annotation for the properties that you don't want to be retrieved. If you have too much data to be annotated, I would suggest you to move those attributes to a single class and have a property on that while it's being annotated with #jsonignore. Mainly this annotation is used to remove cyclic data returned with foreign keys.

Related

I seem to need both #OneToOne and #OneToMany relationship

I'm writing an app to operate a collection of hardware that is supposed to be setup and shutdown repeatedly in different locations.
I want to track those installations so I've created separate entities for a physical object itself and the installation.
Station object needs to keep track of up to one (null while not installed) active installation information (so #OneToOne) but also all the previous installations (so #OneToMany)
#Entity
#Table(name = "station")
class Station{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "stationInstallation", cascade = CascadeType.DETACH,
CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH)
#JoinColumn(name = "station_installation_id", nullable = true)
private StationInstallation activeStationInstallation;
...
#OneToMany(fetch = FetchType.Lazy, mappedBy = "station_id", cascade =
{CascadeType.DETACH, CascadeType.PERSIST,
CascadeType.MERGE, CascadeType.REFRESH })
private List<stationInstallation> stationInstallations;
...
}
The other entity will have the station id, location and date of the setup as well as the shutdownDateTime being null.
#Entity
#Table(name = "stationInstallation")
class StationInstallation{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy ="stationInstallation", cascade - CascadeType.ALL)
private Station station;
#Column(name = "location")
private String location;
#Column(name = "setupDateTime")
private LocalDateTime setupDateTime;
#Column(name = "shutdownDateTime")
private LocalDateTime shutdownDateTime
}
Finally the shutdown method is supposed to unattach the entity from the Station entity by setting activeStationInstallation to null and setting shutdownDateTime to LocalDateTime.NOW.
...
stationInstallation.getStation().setActiveStationInstallation(null);
stationInstallation.setShotdownDateTime(LocalDateTime.NOW);
...
But that will obviously result in a growing number of StationInstallation "finished" objects, which would seem to require #ManyToOne relation with the Station all the while I want to keep #OneToOne relation with the activeStationInstallation.
What do?
I figured I could just make another entity calling it FinishedStationInstallation, remove shutdownDateTime from StationInstallation, make both immutable and instead of adding shutdownDateTime with a setter add it in the constructor while deleting the active version. And immutablity is an asset, ut at the same time I'd have to add several new tables to the db and keep track of and query two entities instead of one.
EDIT: I guess I could get rid of List stationInstallations from the 1st entity, since I don't really need to keep the track of it beyond db queries, but I added it for the clarity of the question.
I would model it this way:
#Entity
#Table(name = "station")
class Station{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.DETACH,
CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH)
#JoinColumn(name = "station_installation_id", nullable = true)
private StationInstallation activeStationInstallation;
...
#OneToMany(fetch = FetchType.Lazy, mappedBy = "station", cascade =
{CascadeType.DETACH, CascadeType.PERSIST,
CascadeType.MERGE, CascadeType.REFRESH })
private List<stationInstallation> stationInstallations;
...
}
#Entity
#Table(name = "stationInstallation")
class StationInstallation{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne(mappedBy ="stationInstallation", cascade = CascadeType.ALL)
private Station station;
#Column(name = "location")
private String location;
#Column(name = "setupDateTime")
private LocalDateTime setupDateTime;
#Column(name = "shutdownDateTime")
private LocalDateTime shutdownDateTime
}
The one-to-one relation from Station to installation has a FK => so no mapped by
The one-to-many relation from Station to installation is mapped by the station association on installation, which obviously has to be a many-to-one association, since the other side is a one-to-many

Map primary key to composite key in JPA

I have 2 tables namely user & user_session.
User table has user_id as a primary key which is referrers to user_session table.
Plus user_session has composite key including session_intime and user_id.
I have designed my entity in JPA. Now I want to map these two entities. I have tried to map these two tables. But my application build failed. Can you please help me out?
#Entity
#Table(name="user")
public class User {
#Id
#Email
#Column(name = "user_id")
private String userId;
#Column(name = "password")
private String password;
#Column(name = "fname")
private String fname;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "userId", referencedColumnName = "user_id")
private UserSession userSession;
}
#Entity
#Table(name="user_session")
public class UserSession{
#EmbeddedId
private UserSessionPK userSessionPK;
#Column(name = "remote_ip")
private String remoteIp;
}
#Embeddable
public class UserSessionPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "user_id")
private String userId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "time_in")
private Date timeIn;
}
I want to map user_id of User table to user_id of UserSessionPK. I am new to JPA, so I don't know how to map with embeddable class.
Remove the mappedBy attribute. This attribute is used when you have bidirectional relationship to indicate which side of the relationship is the owner.
But you will need to set the Foreign Key aka JoinColumn
#JoinColumn("user_id")
#OneToMany(fetch = FetchType.LAZY)
private UserSession userSession;

Can't delete child entity without deleting parent entity, regardless of CascadeTypes?

I'm trying to connect an entity (User) to entities they create which will be Surveys.
I have two repositories, one UserRepository and one SurveyRepository. I can load Surveys according to which User has them and currently they are all mapped by the User_ID, which is a field on the Survey entity.
However, when I try to remove a Survey, this removes my User whenever I define CascadeType.ALL.
But when I don't use that, I get another error "Caused by: java.sql.SQLIntegrityConstraintViolationException:"
I'm gussing this is all related to the password encryption I'm using, but I am not even trying to delete the User entity, I'm just deleting the Survey, which holds a reference, or an ID to the Survey..
I've tried CascadeType.All on both sides, and I've tried not having any CascadeType at all as well.. If I have it on both sides, this deletes the user whenever I tell my surveyRepository.delete(currentSurvey);
And whenever I don't have it on both sides, I get the exception above..
User Entity:
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long id;
#NotEmpty
#Email
#Column(unique = true)
private String email;
private String password;
#NotBlank
private String username;
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#NotBlank private String role;
#OneToMany(fetch = FetchType.EAGER)
private Set<Survey> surveys = new HashSet<>();
Survey Entity:
#Entity
#Table(name = "survey")
public class Survey {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "survey_id")
private Long id;
private String title, creator, description;
private LocalDate date = LocalDate.now();
#OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "survey_id")
#OrderBy("position ASC")
private Set<Question> questions = new HashSet<>();
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
I'm just not sure how I can tell JPA/Hibernate not to touch the User whenever we delete the Survey.
It doesn't matter if I save the User with Survvey or not does it?
Basically I've tried a lot of options and I figure I'm not quite grasping the issue, and I suspect it's about the annotations on the User side, but I still feel as if I should be able to delete the child entity with no problem at all since I am not touching the parent entity?
This is because of EAGER fetch type in User class for surveys.
You delete survey but because it is existed on surveys set in user yet, it wouldn't be deleted actually.
You need to do like this:
// User class
#OneToMany(cascade=CascadeType.ALL, orphanRemoval=true, mappedBy="user")
private Set<Survey> surveys = new HashSet<>();
//Survey class
#ManyToOne
#JoinColumn(name = "user_id")
private User user;

#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.

Spring JPa Id empty

I have an entity who own many object
#Entity
public class Lodger implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long lodgerId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "lodger")
private List<IdentityCard> identityCardList;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "lodger")
private List<Phone> phoneList;
...
}
#Entity
public class IdentityCard {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long identityCardId;
private String identyCardValue;
#OneToOne
#JoinColumn(name = "identity_card_type_id") //without -> identity_card_type_identityCardTypeId
private IdentityCardType identityCardType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lodger_id")
private Lodger lodger;
}
When i save my lodger, all my object is saved (identiyCard, phone), but their field lodger_id is null.
I was thinking it was supposed to be done automatically when we use cascadeType.all.
The owner side of the bi-directioinal associations are in IdentityCard and Phone entities, this is the same as saying that the mappedBy is in Lodger's associations.
So for the persistence of the links you must set the lodger attribute in IdentityCard and Phone entities. Isn't necessary to add this entities to the Lodger's collections but it is fine because you want to save this entities along with Lodger using cascade option.

Resources