Firstly, I don't know if this is possible, as i think the solution would combine two existing JPA features into one: Element Collections and Discriminator Columns.
As stated below, i know how to achieve the solution using ONLY discriminators, however this would be a cumbersome implementation given the requirements stated below.
I have a Wiget pojo, that will have optional filters to reduce the content displayed. At the moment, i have two pojos that can be used as filters (there will be more) the classes below are simplified versions of the classes (they contain a lot more, but I've stripped them down to the relevant information):
Cell:
@Entity
@Table(name = "Cell")
public class Cell implements java.io.Serializable {
private Integer cellId;
private String cell;
private String description;
...
}
Task:
@Entity
@Table(name = "Task")
public class Task implements java.io.Serializable {
private Integer taskId;
private String task;
...
}
What i want to achieve is have one Table (a @CollectionTable?) that contains references to both of these pojos without the need for a "join pojo". Unless I've misunderstood, this is the point of an @ElementCollection.
The number of filter pojos to be filtered on will be expanded, and could potentially incorporate most of the pojos already in the system, i don't want to have to create multiple "join" pojos just to maintain all possible filters, when i could instead just maintain some static integers that reference the pojo type in a similar way that a discriminator column works
So in the Widget, it would look like:
Widget:
@Entity
@Table(name = "Widget")
public class Widget {
private Integer widgetId;
private String colour;
private String description;
private Date fromDate;
private Date toDate;
private Set<Cell> cellsFilter = new HashSet<Cell>();
private Set<Task> tasksFilter = new HashSet<Task>();
...
}
The filters (cellsFilter and tasksFilter) are optional (could have no filters at all).
And the Table that represents the @CollectionTable would look like:
╔═════════════════╗
║ WidgetFilters ║
╠═════════════════╣
║ id ║
║ widgetId ║ <- Should join to the Widget.widgetId column
║ pojoType ║ <- Integer, 1 = cell, 2 = task etc...
║ pojoId ║ <- Should join on the id of the cell or task (or other)
╚═════════════════╝
I've done a similar thing with @DiscriminatorColumn, however this would require me to create an abstract Filter object, CellFilter and TaskFilter (and one for every other filter eventually created).
The closest example i can find is https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection however this is only linking one pojo type (Phone) with one join (the employee id), i need to link to pojoId to the correct pojo type based on the pojoType column AND join it to the Widget based on the widgetId.
FYI, I've tried things like joins with where clauses, various combinations:
@ElementCollection(targetClass=Cell.class)
@JoinTable(
name="WidgetFilter",
joinColumns=@JoinColumn(name="widgetId", referencedColumnName="widgetId"),
inverseJoinColumns=@JoinColumn(name="pojoId", referencedColumnName="cellId")
)
@Where(clause = "pojoType = 1")
public Set<Cell> getCellsFilter() {
return cellsFilter;
}
This is a difficult concept to google, given all the "similar, but not quite" answers available
If it's not possible, that's fine, at least i know how to proceed, but if anyone has achieved this already, any help would be appreciated.
My Current Solution:
The only way i can think of doing this would be to create just one Filter pojo that represents the WidgetFilter Table row, and make the Widget pojo include logic that resolves a List<Filters> into the correct types itself (without any fancy annotations) like so...
Widget:
@Entity
@Table(name = "Widget")
public class Widget {
private Integer widgetId;
private String colour;
private String description;
private Date fromDate;
private Date toDate;
private Set<Filter> filters = new HashSet<Filter>();
private Set<Cell> cellsFilter = new HashSet<Cell>();
private Set<Task> tasksFilter = new HashSet<Task>();
...
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "filter")
public List<Filter> getFilters() {
return this.filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
setCellFilters(filters);
setTaskFilters(filters);
}
@Transient
public List<Cell> getCellsFilter() {
return this.cellsFilter;
}
public void setCellsFilter() {
List<Filter> cellFilters = filters.stream().filter(f -> f.getPojoType().intValue() == Filter.CELL).collect(Collectors.toList());
// get List<Cell> from database from List<Filter>
}
@Transient
public List<Task> getTasksFilter() {
return this.tasksFilter;
}
public void setTasksFilter() {
List<Filter> taskFilters = filters.stream().filter(f -> f.getPojoType().intValue() == Filter.TASK).collect(Collectors.toList());
// get List<Task> from database from List<Filter>
}
...
}
Filter:
@Entity
@Table(name = "Filter")
public class Filter{
public static final int CELL = 1;
public static final int TASK = 2;
private Integer filterId;
private Widget widget;
private Integer pojoType;
private Integer pojoId;
...
}
Cheers,
Steve.