JPA reusable entity and relationship - java

I am trying to build an app with Spring Boot and PostgreSQL where I want to store a Game entity.
The Game has a Setting which has many variation but still limited. I think its worth storing as separate Entity and reuse it for games with the same setting.
#Entity
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Game {
#Id
#GeneratedValue
#Type(type = "pg-uuid")
private UUID id;
private Setting setting;
// etc, players and game result related stuff
}
#Entity
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Setting {
#Id
#GeneratedValue
#Type(type = "pg-uuid")
private UUID id;
private String format;
// etc, other customizable settings
}
Want I would like to achive is
To create the Setting entity only if it does not exist. What is the
best way to do this validation?
To setup the right relationship between the Game and Setting. One
Setting entity can belong to any number of Game but one Game can only
have one Setting.
Thank you

To create the Setting entity only if it does not exist. What is the
best way to do this validation?
Adding a new row to your Setting table only if it does not exist needs more specification
You could take this literally and once you
get a Setting in a request check your whole Setting table for one
that matches all of the values of the Setting that you received, if
it exists OK, if it does not exist you save a new one.
However, since you said the settings are limited I would suggest presenting the user with a list of available settings and letting them pick one of those, and having an option to add a new setting if they wish so. If you really want to validate if an exact match to that setting does not exist already, then you can do your validation at this point as well.
To setup the right relationship between the Game and Setting. One Setting entity can belong to any number of Game but one Game can only have one Setting.
This simply requires you to have a setting foreign key in your Game table
Your Game entity class would look like this:
#Entity
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Game {
#Id
#GeneratedValue
#Type(type = "pg-uuid")
private UUID id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="setting_id")
private Setting setting;
// etc, players and game result related stuff
}

Related

How do I get hibernate to eagerly fetch EmbeddedId?

I occasionally get the following error:
org.hibernate.LazyInitializationException: could not initialize proxy [com.dd.translation.domain.postgres.Offer#OfferKey(offerId=03Y, difId=b3e79b1925ce4e41905a2ce214943d1f)] - no Session
Embeddable:
#Builder
#Embeddable
#Data
#NoArgsConstructor
#AllArgsConstructor
public class OfferKey implements Serializable {
#Column(name = "offer_id", columnDefinition = "CHARACTER VARYING(64) NOT NULL")
private String offerId;
#Column(name = "dif_id", columnDefinition = "CHARACTER VARYING(64) NOT NULL")
private String difId;
}
Embedded object:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Table(name = "offers")
public class Offer {
#EmbeddedId
private OfferKey offerId;
private LocalDateTime validDate;
}
There is no other lazy loading in this project and I wouldn't assume I would need #Transactional for it. I am trying to figure out if there is a way to manually set it to eager or if anyone has run into this issue. I personally do not use this pattern but it is in existing code and I am trying to figure out if I need to rip it out or if there is an easy fix.
The error is telling you that the Offer object you are trying to access is not initialized, not the embedded id.
I guess you have something like this in one of your models:
#ManyToOne(fetch = FetchType.LAZY)
Offer offer;
Wherever you load the entity containing that association, you will have to make sure the offer is properly initialized, as apparently the calling code expects it can access offer details.
You can change the FetchType to EAGER, but I wouldn't recommend that. The better solution would be to apply a #EntityGraph on the repository method that instructs it to load the association.

How to model a three-way relationship in a JPA Spring Boot micro service with a MySQL back end

I have created a Spring Boot JPA micro service with a MySQL back end. I have two simple entities in my model, users and skills. These are used to represent the skills base within my organisation. Each user may have many skills and so I have used a one to many join to model this and can successfully assign skills to users. In my database, I can see that a users_skills table has been created by JPA to achieve this.
However, I am now struggling because, for each skill that a user has, an experience level needs to be specified (e.g. basic, advanced, expert) and I am unsure how to achieve this. I'm not sure whether 'levels' should just be an enum type within the Skill entity, or perhaps it should be a separate entity in its own right? Could I configure JPA so that it generates a users_skills_levels table which would represent this three-way relationship? Any advice would be most welcome!
These are my Entity classes: -
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
private String email;
#OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
private Set<Skill> skills = new HashSet<>();
getters and setters
}
#Entity
#Table(name = "skills")
public class Skill {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
private String name;
getters and setters
}
That's not possible what you try to achieve.
You should create an Entity for the users_skills_levels. E.g. UserSkillLevel This entity will then have a ManyToOne relationship to User and a ManyToOne relationship to Skills plus the attribute level.
The User has a collection of UserSkillLevel and the Skill entity as well.
Please find a more in-depth example here:
https://thoughts-on-java.org/many-relationships-additional-properties/

Can we create a JPA mapping not matching the database constraints?

Lets assume I have the following domain model:
users
----
id (PK)
partitionkey (PK)
In the above table, the partition key is primarily used for partitioning. (MySQL requires the partitionkey to be part of the primary key). If we assume the record can be uniquely identified by the id field only, is there any harm in skipping partitionkey in the mapping. For example, is the mapping below valid:
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
public Long id;
#Column(name="partitionkey")
private Long partitionKey;
}
Try to define a separate #Embeddable object with the PK fields and use it as #EmbeddedId in your #Entity class like this:
#Embeddable
public class MyCompositePK {
#Column(name="id")
private Long id;
#Column(name="partitionkey")
private Long partitionKey;
}
#Entity
#Table(name = "users")
public class User implements Serializable {
#EmbeddedId
private MyCompositePK id;
...
}
Yes, it's valid. JPA provider is not aware of any constraints or other features that exist in the tables to which entities are mapped.
However, is it a good approach, especially because we're talking about partitioning here? Keep in mind that entities are associated via ids. So, for each entity that is associated with User, JPA provider will search the associated User instance by id column only, thus partitioning column will not be included in the query. This may or may not be a problem. See this answer as well for more details.
The alternative could be using provider specific extensions like #JoinFormulas in Hibernate, but they may not be easy to get right.
I would say that going with composite ids is the most straightforward solution to go.

update on many-to-one hibernate relationship no works

I have a problem with hibernate relationship many-to-one.
My system is commercial proposal controller, where has a responsible for proposal from user entity. When the proposal is create and set the responsible, has no problems, works fine. But when change the responsible and update, it changes the object, I can see in a datatable, but has no update in database. If I refresh on page the update disapears.
#Entity
#Table(name = "proposal")
public class Proposal implements Serializable {
#Id
#GeneratedValue
private Integer id;
#ManyToOne
private User responsible;
............
DAO Code
public void update(Proposal proposal) {
this.session.update(proposal);
}
In the User class I don't make any annotation about this relationship, it's a unidirectional relationship. The class proposal yet use the user class to make a user's bag, as participants, and this relationship will be unidirectional relationship too.
I tried to make annotations in user class but no works too.
User class with annotations
#Entity
#Table(name="user")
public class User implements Serializable{
#OneToMany
private List<Proposal> proposal;
The class User has a many-to-one relationship with userType and it works fine.
#Entity
#Table(name="user")
public class User implements Serializable{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "idType, nullable = true)
private TipoUsuario userType;
Someone has any ideia about this?
Thanks
You'll see changes after flushing to database. Either manually - flush() or after transaction has been committed. The User class - must be either an entity (both #Entity and #Id annotations are needed) or embedable class and should be configured in the corresponding way in this case.
I'm not sure how it works if you say - #Entity without #Id for User, but try again:
Run flush for User. If you won't get any exception - it is a persisatble object. You should see in db/web application log files - sql insert query.
Commit transaction. The updated value of User should be committed.
If you invoke refresh, before commit, all your changes will be lost.
It looks to me like you're missing the #JoinColumn annotation from your ManyToOne relationship with your User. Try updating to this:
#ManyToOne
#JoinColumn(name="userId")
private User responsible;
But obviously replace 'userId' with the id name as its specified in your table.

Toplink JPA Inheritance - Summary/Detail relationship

I'm using toplink JPA in a webapp and I want to map just one table to a class hierarchy. I want to have one class that represents most of the data, and one class that inherits from that (so it gets all the fields of the superclass, plus a couple of other that hold large amounts of data). I don't want the large amounts of data all the time, don't want to hold them in request objects etc. I only want the large bits when someone has selected one of the summaries. I've setup the classes as follows (simplified as an example).
#Entity
#Table(name = "TRANSCRIPTS")
#MappedSuperclass //also tried without this - same error
public class Summary {
#Id
#Column(name = "id")
private long id;
#Column(name = "title")
private String title;
//rest of class etc.
}
#Entity
#Table(name = "TRANSCRIPTS")
public class Detail extends Summary {
#Id
#Column(name = "fullText")
private String fullText;
//rest of class etc.
}
When I try and get data using this hierarchy, I get an error along the lines of
Unknown column 'DTYPE'
So it's looking for a descriminator column. Which I haven't setup, because it's not that sort of relationship.
Is there a different way I can map this summary/detail relationship in JPA? Or should I give up on the class inheritance and have two separate unrelated classes, one representing summary data and one representing the full data (and redefining the summary fields).
Thanks.
DTYPE it is discriminator column that Toplink tries to access to choose between your entities,
If you add that column to your table schema, it will start working.
DTYPE is INTEGER typed column in database.
You could specify your own discriminator column using following code snippet:
#Entity
#DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.INTEGER)
#DiscriminatorValue("1")
class TestClass {}
Here is some documentation for you http://www.oracle.com/technetwork/middleware/ias/toplink-jpa-annotations-096251.html#CHDJHIAG

Categories