EDIT: For those who may pass through here in the future, I'd like to share something I found. Although it's not going to work for this particular situation, hibernate does have an #Where annotation. With this annotation you could have N amount of Sets. Each set would have #Where(clause='column=value'). I will not be using the #Where solution but it may work out for you.
I'm new(ish) to JPA Hibernate and am looking for some help. I don't necessarily know what to search for either so here is a quick example of my problem.
I need to take a Set and split it into multiple Set dependent on a value of a field.
Lets look at something simple:
public class Customer{
private String name;
private String age;
private Set<Order> orders;
}
public class Order{
private int amount;
private String status;
}
Goal: I would like to have Hibernate split my Customer's orders by their status into seperate Sets. Currently I use the #POSTLOAD annotation to loop over the Set and seperate them out accordinly. I would prefer Hibernate do it for me resulting in something like:
public class Customer{
//Irrelevant stuff from above...
private Set<Order> pendingOrders;
private Set<Order> completedOrders;
private Set<Order> canceledOrders;
}
These sets would be based off the order's status.
pendingOrders is where Order.getStatus() == "PENDING"
completedOrders is where Order.getStatus() == "COMPLETED"
canceledOrders is where Order.getStatus() == "CANCELED"
The tables are directly represented by the classes and are both considered "Entities". (Customer and Order)
If I haven't provided adequate information, could you please point me to a proper search for what I am "trying" to accomplish. In terms of JPA terminology I have no idea what to search for and could really use some help!
Thank you!
The best approach in your case is create a discriminator column and some extra classes to use it. Example
#Entity
#Table(name = "ORDER")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "STATUS", discriminatorType = DiscriminatorType.STRING)
public abstract class Order{
}
#Entity
#DiscriminatorValue(value = "PENDING")
public class PendingOrder extends Customer {
}
public class Customer{
//Irrelevant stuff from above...
private Set<PendingOrder> pendingOrders;
//same fo0r all others types
}
And if you notice the orders have some specific information only valid for pending orders or completed orders, then probably the best approach is use
#Inheritance(strategy = InheritanceType.JOINED)
Or
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
And add the specific columns in those new tables
Related
) I have some problem with sorting and spring pageable when I use QueryDSL. I need quite advanced sorting, not just by the fields of the object stored in the database in the same table.
This is my model in approx:
#Getter
#Setter
#Entity
public class Book {
#Id
#GeneratedValue
private long id;
#OneToMany
private Set<Category> cats = new HashSet<>()
}
#Getter
#Setter
#Entity
public class Category{
private long id;
private Name name;
}
public enum Name{
WINTER,
SUN,
SUMMER
}
Now, this what I want to do is sort (desc and asc) Book (I have many Books) by Category id only if Category has name SUN. And i want to pass Qsort as Sort interface to PageRequest sping class.
I have no idea how I can achieve it. I try many way but none of these are even close to resolve this problem (for example some subquery with invoke any() on collection and use Qsort class). I affraid I made a mistake using Query DSL rather than Criteria Api. Can someone direct me? I will be very grateful.
Best Regards
I have two objects in my model:
#Entity
#Table(name = "project")
#Getter
#Setter
public class Project extends BaseData{
...
private PaymentMethod paymentMethod;
...
}
.
#Getter
#Setter
public class PaymentMethod {
private Boolean requestRequired;
private Integer timeLimit;
}
What I want to do is to map requestRequred and timeLimit fields on columns of project table so there is no need to create one more table to store PaymentMethod objects in.
Is it possible in general and is it a common practice to do this? It seems a little bit counterintuitive for me and difficult to maintain. But on the other side a lot of tables lead to performance issues as far as I know.
Thanks for help!
I know there are several questions on this argument, but I think mine is a bit different.
I'm trying to use JPA notation instead of XML mapping. In my queries always there's an undesired dtype column, and I don't want to use neither discriminator column and formula.
I have four classes as follow:
The first named ObjectUUID. All classes extend this super class.
This class is used only to define id field, as follow:
#MappedSuperclass
public class ObjectUUID {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
protected String id;
// getter and setter and other static methods
}
Then I have another class, named TrackSys where I define other fields (as insert date and update date) as follow:
#MappedSuperclass
public class TrackSys extends ObjectUUID{
#Column(name="dt_ins")
private CustomCalendar dtInsert;
#Column(name="dt_upd")
private CustomCalendar dtUpdate;
// getter and setter
}
the third and the forth classes are beans mapped on DB, as follow:
#Entity
#Table(name="patient")
public class PatientUUID extends TrackSys {
}
#Entity
#Table(name="patient")
public class Patient extends PatientUUID {
#Column(name="surname")
private String surname;
#Column(name="name")
private String name;
#Column(name="cf")
private String cf;
// getter and setter
}
I define a repository to query my patient table, as follow:
public interface PatientRepository extends JpaRepository<Patient, Long> {
List<Patient> findBySurname(String surname);
}
When my Patient query runs, the generated SQL is the follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.dtype='Patient'
and patient0_.surname=?
Now...
I don't want dtype column and I don't want to use discriminator formula.
With the XML mapping this is possible without particular properties to specify.
With JPA annotation I try in order:
Use #Inheritance(strategy = InheritanceType.SINGLE_TABLE) but dtype is always present
Use #Inheritance(strategy = InheritanceType.JOINED) but dtype is always present
Now, my feeling versus dtype is only hate, how can I get this simple query, as follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.surname=?
I am not very experienced with JPA and was curious if the following is possible.
Say I have a class Project as follows:
#Entity
public class Project {
#Id
private String projectCode;
private String departmentId;
/*
* Is something like this possible with JPA?
*/
if (departmentId == null) {
#JoinColumn(name = "projectCode", referencedColumnName = "assignedProject")
} else {
#JoinColumn(name = "departmentId", referencedColumnName = "id")
}
#OneToMany(targetEntity = Employee.class)
private List<Employee> contributors;
// getters/setters
}
So I would like to populate the contributors list based on the presence of departmentId.
Is this possible with JPA? Or will I have to specify two List<Employee> fields, mapped by both variables, and preform proper checks within my application logic?
Thanks for your help.
/*
* Is something like this possible with JPA?
*/
if (departmentId == null) {
#JoinColumn(name = "projectCode", referencedColumnName = "assignedProject")
} else {
#JoinColumn(name = "departmentId", referencedColumnName = "id")
}
No, this isn't possible with JPA and you'll be glad that it isn't.
You can achieve what you want by using inheritance in Java. Begin by creating an abstract entity that contains all the common fields of your table. Then you can create an entity subclass with a projectCode attribute and another entity subclass with a departmentId attribute.
At the RDBMS level, for a simple object model like the one we just built, a single table can be mapped. In the abstract entity, you would annotate as follows to achieve this:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DTYPE", discriminatorType = STRING, length = 1)
#DiscriminatorValue("?")
#Entity
public abstract class Project {
:
:
}
#DiscriminatorValue("P")
public class ProjectCodeProject extends Project {
:
:
}
Remember that RDBMS has no knowledge or notion of inheritance. Inheritance exists only on the Java side. In the database, inheritance is represented by metadata. The "Discriminator" is a special column (here named "DTYPE") that appears in your database table that informs JPA which subclass a particular column represents. In the above, the code "P" was chosen to represent database records that have a PROJECTCODE attribute rather than a DEPARTMENTID attribute.
Using a class hierarchy like this would enable you to have a table whose rows can have either a departmentId or a projectCode as an attribute (not both). Because rows of the table are all Projects, developing common logic in Java to work with the subtypes ought to be relatively straightforward.
I want to achieve something like this:
#Entity
#Table(name = "beer")
public class Beer {
#Id Long id;
String brand;
String name;
}
#Entity
public class BeerWithIngredients extends Beer {
#OneToMany(mappedBy="beer")
List<BeerIngredient> ingredients;
}
#Entity
public class BeerIngredient {
#Id Long id;
// .. whatever fields
#ManyToOne
#JoinColumn(name = "beer_id")
BeerWithIngredient beer;
}
Physically, all beer data is in one table, but I want to split it into more entities.
Please note that:
I would not like to use discriminator column in the database
There isn't a column that I could use for #DiscriminatorFormula
I do not want to embed Beer inside BeerWithIngredients, because it essentially is not a composition, but proper inheritance
Is there a way of achieving this with JPA (Hibernate)? Right now it complains about missing discriminator column, that I don't plan to provide.
Introduce a new super class RootBeer with all common beer properties. Annotate this class with MappedSuperClass. Make Beer and BeerWithIngredients inherit from RootBeer and annotate them with Entity as well as Table(name="beer").
For an example check this.