I have the following Pojo:
#Entity
#Table(name = "USER")
class User {
#Id
private long id;
private String name;
private int age;
private long lastVisited;
private long lastPlayed;
private long lastPayed;
...
}
I would like somehow if possible to map the Pojo like this:
#Entity
#Table(name = "USER")
class User {
#Id
private long id;
private String name;
private int age;
#Embedded
private UserStatistics statistics;
...
}
#Embeddable
class UserStatistics {
private long lastVisited;
private long lastPlayed;
private long lastPayed;
}
BUT, I DON'T want to move the statistics columns into a new
USER_STATISTICS table and do #OneToOne mapping.
Is there a Hibernate trick I can use here?
Thanks!
What you did is already enough, Hibernate does not require you to define fields for all columns in your table. It's rather the other way around - all non-transient fields should be reflected as columns in the corresponding table either using name defined in #Column annotation or generated using a naming convention used in hibernate configuration.
The example you presented is sufficient and will work, but I wouldn't recommend it as you can have two entities mapping single row at the same time.
Related
I'm trying to write a controller that will function as multiple seat reservation.The Integers list is used for filtering.
My Entity looks like this:
#Entity
#Id
private movieId;
private String movieName;
private String cinemaName;
private String cinemaHall;
private Intger seatingPlace;
private boolean booked;
How Can I pass list or sets in request body to access multiple update seatingPlace. Did I modyfing Enity or connect in smthing relation?
Acutally my multipleUpdate API works using JPA Query findByMovieNameAndCinemaNameAndcinemaHall and return me list wchich
I checking isnt Empty and cheking (field boolean booked) if true so ok u can booked them.
And after that i want filter by passing List seatingPlace and change boolen to false.
Based on my understanding of your requirements, a possible solution could be creating another entity (table) MovieSeatReservation and creating a One to Many relationship from your Entity. It could look like this: (You can replace Entity class name with your real entity name)
#Entity
public class Entity {
#Id
#GeneratedValue
private Long movieId;
private String movieName;
private String cinemaName;
private String cinemaHall;
#OneToMany
private List<MovieSeatReservation> reservedSeatsStatus;
// getters and setters
}
#Entity
public class MovieSeatReservation {
#Id
#GeneratedValue
private Long id;
private boolean isReserved;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "movie_id")
private Entity entity;
// getters and setters
}
I have entity called Shop and different types of shops (sport, clothes, tech...). That list of types will probably be predefined. One shop can have multiple types. What is the best way to represent that?
I created two entities Shop and Type.
#Entity
#Table(name = "store")
public class Store {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
...
}
#Entity
#Table(name = "type")
public class Type {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
private String name; //sport, clothes, tech...
}
What type of relationship between these two entities should I use?
Given that you said Type is probably predefined, it seems more reasonable to model it as enum, and making use of ElementCollection
(I have to admit that I haven't tried to use them both in combination, I believe it should work though :P )
public enum Type {
SPORT, CLOTHES, TECH
}
public class Shop {
#Id
private Long id;
#ElementCollection
#CollectionTable(
name="SHOP_TYPE",
joinColumns=#JoinColumn(name="SHOP_ID")
)
#Column(name="TYPE")
// mapping for enum by usertype or other way, depending on JPA version you are using
private List<Type> types;
}
Of course, you can model SHOP_TYPE as an entity (e.g. ShopType) if you want more complicated operations on it, but what described above looks to me a more reasonable domain model.
Even you do not want the Type to be predefined (i.e. you can create whatever type in your application), it is still more reasonable to model it as a ManyToMany relationship:
public class Type {
#Id
#Column(name="TYPE_ID")
private Long id
#Column(name="TYPE_NAME")
private String name;
}
public class Shop {
#Id
#Column(name="SHOP_ID")
private Long id;
#ManyToMany
#JoinTable(
name="SHOP_TYPE",
joinColumns=#JoinColumn(name="SHOP_ID"),
inverseJoinColumns=#JoinColumn(name="TYPE_ID"))
private List<Type> types;
}
Just one thing to note: It does not look right to have a Type entity which contains a String as type name, and refer to Shop (as some of the answer suggested). Type should be an entity of itself, and, for example, different shops having CLOTHES type should refer to same CLOTHES entity (unless you view types as some kind of arbitrary tag)
The Store and Type many to many relationship is linked with a third / join table named STORE_TYPE_MAPS.
Store Entity:
#Entity
#Table(name = "store")
public class Store {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
#ManyToMany(fetch = FetchType.LAZY, targetEntity=Type.class)
#JoinTable(name="STORE_TYPE_MAPS",
joinColumns=#JoinColumn(name="STORE_ID"),
inverseJoinColumns=#JoinColumn(name="TYPE_ID")
private Set<Type> types;
//... getter-setter
}
If Type is an Entity then make it ManyToMany
#ManyToMany
#JoinTable(name="Store_Type")
private List<Type> types;
also it can be an enum
I rather prefer to create a new entity called ShopType, the ManyToMany relationship will be created as explained below.
This new Entity allows you to have extra columns in the join table, "ShopType", (which can't be done with a simple #ManyToMany). For example, you can add this information: "the number of articles of each type in each shop".
The code is as follows:
public class Shop {
#Id
#Column(name="SHOP_ID")
private Long id;
#OneToMany(mappedBy = "shop", cascade = CascadeType.ALL)
private List<JoinAchatType> joinShopType = new ArrayList();
}
public class ShopType {
#ManyToOne
#JoinColumn(name = "SHOP_ID")
private Shop shop;
#ManyToOne
#JoinColumn(name = "TYPE_ID")
private Type type;
private int numberArticle;
}
public class Type {
#Id
#Column(name="TYPE_ID")
private Long id;
#OneToMany(mappedBy = "type", cascade = CascadeType.ALL)
private List<JoinAchatType> joinShopType = new ArrayList();
}
For more information check these links:
Mapping many-to-many association table with extra column(s)
.
The best way to use the #ManyToMany annotation with JPA and Hibernate.
I've got 2 tables vehicle and vehicle_image. The vehicle table contains all master data of the vehicles and the vehicle_image table contains the meta information of the images and the Base64 encoded string of the image. On vehicle may have 0 or more images.
Now when I query the vehicle object I'd like the object to contain the information from the vehicle_image table.
I'm pretty new to JPA and the examples I could find always seem to read only one value from another table, not a list.
What would be the simplest way of adding an attribute to the vehicle object that contains the image data?
#Entity
#XmlRootElement(name = "vehicle")
public class Vehicle {
#Id
private String vin;
private String commission;
#Column(name="swiss_type_number")
private String swissTypeNumber;
#Column(name="sale_type")
private String saleType;
#Column(name="exterior_color")
private String exteriorColor;
#Column(name="interior_color")
private String interiorColor;
private String remarks;
#Column(name="additional_title")
private String additionalTitle;
#Column(name="added_value_description")
private String addedValueDescription;
#Column(name="first_registration")
private String firstRegistration;
private String guaranty;
#Column(name="last_inspection")
private String lastInspection;
private int dealer;
private int mileage;
private int price;
private int seats;
#Column(name="model_year")
private int modelYear;
#Column(name="car_damaged_in_accident")
private boolean carDamagedInAccident;
private boolean imported;
// List of images
List<VehicleImage> vehicleImages; // Something like this would be nice
}
JPA supports associations between entities. The one you need is #OneToMany
If your vehicle_image' table contains columnvehicle_idyou will need following mapping inVehicle` class:
#Entity
#Table(name = "VEHICLE")
#XmlRootElement(name = "vehicle")
public class Vehicle {
// other fields here
#OneToMany(mappedBy = "vehicle")
Set<VehicleImage> vehicleImages;
}
And also this in VehicleImage
#Entity
#Table(name = "VEHICLE_IMAGE")
public class VehicleImage{
// other fields here
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name="VEHICLE_ID", referencedColumnName = "ID")
Vehicle vehicle;
}
Also you should better use Set for collections mapping in JPA, but it is a different topic
What you have here is a one-to-may relationship, you can use:
#OneToMany
List<VehicleImage> vehicleImages;
Refere to the javadoc for the attributes it may take and add them according to your table definitions.
Here you can find some examples of how to use it.
I have an Evaluation entity that has an associated list of EvaluationEvaluator. I need to explicitly create that entity because it required an extra column "STATUS". Before I continue evaluation. I do: evaluation.setEvaluationEvaluator(listEvaluator) where listEvaluator is a list of EvaluationEvaluator type. Then persist(evaluation). When I run this, it does not throw any kind of exception. But in the database, it inserts in the Evaluation table, and not inserted into the EvaluationEvaluator table.
Below my Evaluation entity.
#Entity
public class Evaluation implements Serializable{
#Id
#GeneratedValue
private Long id;
//MORE FIELDS
#OneToMany(mappedBy="evaluation")
private List<EvaluationEvaluator> evaluators;
//CONSTRUCTORS
//GETTER AND SETTERS
}
This is my EvalutionEvaluator Entity:
#Entity
#Table(name= "EVALUATION_EVALUATOR")
#IdClass(EvaluationEvaluatorId.class)
public class EvaluationEvaluator implements Serializable{
#Id
#Column(name="EMPLOYEE_ID", insertable=false , updatable=false)
private Long EmployeeID;
#Id
#Column(name="EVALUATION_ID", insertable=false, updatable=false)
private Long EvaluationID;
#ManyToOne
#JoinColumn(name"EMPLOYEE_ID")
private Employee employee;
#ManyToOne
#JoinColumn(name"EVALUATION_ID")
private Evaluation evaluation;
#NotNull
private String status;
//CONSTRUCTORS
//GETTER AND SETTERS
}
This is my EvaluationEvaluatorId class
public class EvaluationEvaluatorId implements Serializable{
private Long employeeID;
private Long evaluationID;
//CONSTRUCTOR
//GETTER AND SETTERS
}
And finally, this is my EvaluationBean class
#Stateful
#Named
#LocalBean
#ConversationScoped
public class EvaluationBean {
#PersistentContext(type= PersistenceContextType.EXTENDED)
private EntityManager em;
#Inject
Conversation conversation;
private Evaluation evaluation;
//IN MY WEBPAGE I IMPLEMENT PRIMEFACES PICKLIST AND IT REQUIRE DUALIST TO HANDLE
private DualListModel<Employe> evaluators;
private EvaluationEvaluator evaluationEvaluator;
private List<EvaluationEvaluator> listEvaluators;
#Inject
private EmployeeList employeeList;
//GETTER AND SETTERS
public String begin(){
if (conversation.isTransient()){
converstaion.begin();
}
evaluationEvaluator = new EvaluationEvaluator();
listEvaluators = new ArrayList<EvaluationEvaluator>();
evaluation = new Evaluation();
List<Employee> source = employeeList.findAll();
target = new ArrayList<Employee>();
evaluators = new DualListModel<Employee>(source, target);
return "/evalution/evaluationAsig.xhtml"
}
public String save(){
Iterator<Employee> iterator = evaluators.getTarget().iterator();
while (iterator.hasNext()){
EvaluationEvaluator ev = new EvaluationEvaluator();
ev.setEmployee(iterator.next());
listEvaluators.add(ev);
}
evalution.setEvaluationEvaluators(listEvaluators);
if(evaluation.getId()==null){
em.persist(evalution);
} else{
em.merge(evalution);
}
if(!conversation.isTransient()){
convesation.end();
}
return "/evalution/evaluationsAsig.xhtml"
}
}
When I debug my application,apparently everything is correct, but I mentioned above, doesn't persist in EvaluationEvaluator table.
Your #OneToMany association is missing cascading configuration.
Add cascade = CascadeType.ALL or cascade = {CascadeType.PERSIST, CascadeType.MERGE} to the #OneToMany annotation. JPA assumes no cascading by default so you would need to persist each EvaluationEvaluator by yourself explicitely otherwise.
UPDATE
There is another thing wrong with the code - the Ids of EvaluationEvaluators are never assigned. You have a complex key made of two Long columns. Both are marked not insertable nor updatable which tells to JPA that the id is going to be somehow generated on database level and it should not care about it. There is however no sequence configured explicitely in your entity (although it is not necessarily required) and also from your comment:
I did what you recommended but it throws the following exception. "A different object with same identifier was already associated with the session"
I assume that this is not the case and both id column values default to null or zero and are same for all EvaluationEvaluators you are trying to persist. If you'd like the database to generate the id for you automatically use #GeneratedValue - Configure JPA to let PostgreSQL generate the primary key value - here you can find explanation how to do this (the database part is database dependent, this is for PostgreSQL). The most common use case however, is to configure the sequence but let hibernate pick the next value, instructions here - Hibernate sequence on oracle, #GeneratedValue(strategy = GenerationType.AUTO)
It seems to me that there is virtually no difference between the below two ways of mapping. Here is an example base on #MapsId javadoc:
// parent entity has simple primary key
#Entity
public class Employee {
#Id long empId;
...
}
// dependent entity uses EmbeddedId for composite key
#Embeddable
public class DependentId {
String name;
long empid; // corresponds to primary key type of Employee
}
#Entity
public class Dependent {
#EmbeddedId DependentId id;
...
#MapsId("empid") // maps the empid attribute of embedded id
#ManyToOne Employee emp;
}
What if I change Dependent's mapping to:
#Entity
public class Dependent {
#EmbeddedId DependentId id;
#ManyToOne
#JoinColumn("empid", insertable=false, updatable=false)
Employee emp;
}
What is the difference of the above two approach?
So, I tested #MapsId for my usage when in the table I have only one foregin key it was no different. But for tables where I have two foregin keys to one table like ...
UserTable, and EmailTable-> #MapsId(owner)UserTable owner, #MapsId(receiver) UserTable receiver i have problems with that. Hibernate throws exceptions. So i have to back to old #JoinColumn way of doing that. That was a one differemce that I met with that adnotations.
I am using combination of both #MapsId and #JoinColumn together to avoid getting extra field getting created in DB for associating the entities. IF I ignore #JoinColumn, an extra field is getting created in DB.
#Entity
public class BookingsModel implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private SlotDateModel slotDateModelObj;
#JsonProperty
String slotnumber;
#MapsId("memberid")
#JsonBackReference
#ManyToOne
#JoinColumn(name="memberid",referencedColumnName = "memberid")
#NotNull
MemberModel memberModel;
.
.
.
}
#Entity
public class MemberModel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty
#Id
String memberid;
#JsonProperty
String name;
#JsonIgnore
String phoneno;
#JsonManagedReference
#OneToMany
Set<BookingsModel> bookings;
.
.
.
}
#Embeddable
public class SlotDateModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
String memberid;
String slotdate;
.
.
.
}
Tables generated with #JoinColumn
Table generated when #JoinColumn is commented Can notice that the extra field "member_model_memberid" is getting added.