Добрый день.
Столкнулся с проблемой использования стандартного фильтра (в экранах типа Browse) в которых сущность загружается с использование представления (view) в которых есть fetch=‘JOIN’.
Например имеет такие сущности:
public class Employee extends BaseIdentityIdEntity {
...
@JoinColumn(name = "PERSON_ID")
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@NotNull
private Person person;
...
}
public class Person extends BaseIdentityIdEntity {
...
@Composition
@OnDelete(DeletePolicy.CASCADE)
@OneToMany(mappedBy = "person")
private List<PersonNames> personNamesList = new ArrayList<>();
...
}
public class PersonNames extends BaseIdentityIdEntity {
...
@Column(name = "LAST_NAME", nullable = false)
@NotNull
private String lastName = "";
@Column(name = "FIRST_NAME", nullable = false)
@NotNull
private String firstName = "";
@Column(name = "SECOND_NAME")
private String secondName = "";
...
}
Есть экран Browse для вывода списка сущностей Employee, в котором используется view
<view>
...
<property name="person" fetch="JOIN">
<property name="personNamesList" view="_minimal" fetch="JOIN"/>
</property>
...
</view>
Имеется, например, некий набор данных
Таблица Employee
id | person_id | … |
---|---|---|
1 | 1 | |
2 | 2 |
Таблица Person
id | … |
---|---|
1 | |
2 |
Таблица **PersonNames **
id | person_id | last_name | first_name | second_name | … |
---|---|---|---|---|---|
1 | 1 | Иванова | Елена | Александровна | |
2 | 1 | Петрова | Елена | Александровна | |
3 | 2 | Степанова | Ирина | Павловна | |
4 | 2 | Максимова | Ирина | Павловна | |
5 | 2 | Александрова | Ирина | Павловна |
В итоге запрос выглядит типа такого: SELECT ... FROM Employee LEFT OUTER JOIN Person... LEFT OUTER JOIN PersonNames...
.
Такой запрос, очевидно, выведен не 2 строки, а 5. Дальше ORM творит магию, собирает сущности и мы в таблице видим две строки, двух сотрудников.
И когда экран без фильтра, то проблем нет. Сущности загрузились, я каким-то образом выбираю из списка нужное ФИО и отображаю в ячейке таблицы.
Предположим добавили фильтр, который ничего не фильтрует, но в нём установлено число отображаемых строк 2
. В результате этого в конце запроса (БД Postgresql) добавиться LIMIT 2 OFFSET 0
и в итоге в таблице (в экране) вы увидим одну строку, только одного сотрудника. Тут понятно почему это происходит - из-за JOINов и LIMITа.
Вопрос в том, можно ли это как-то победить? И использовать JOINы, и видеть в таблице то количество строк, сколько выбрал (естественно что в БД есть столько сущностей).
Это первый вопрос.
Вопрос второй.
В некоторых ситуациях, как я понимаю, когда много JOINов, примерно как в моём случае, EclipseLink как-то по особенному загружает и собирает результат и у меня возникает ошибка:
Caused by: java.lang.NullPointerException: null
at java.util.ArrayList.<init>(ArrayList.java:178) ~[na:1.8.0_232]
at org.eclipse.persistence.mappings.ForeignReferenceMapping.prepareNestedJoinQueryClone(ForeignReferenceMapping.java:2501) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.mappings.OneToOneMapping.valueFromRowInternalWithJoin(OneToOneMapping.java:1818) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:2200) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.mappings.ForeignReferenceMapping.buildCloneFromRow(ForeignReferenceMapping.java:350) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.mappings.ForeignReferenceMapping.buildCloneFromRow(ForeignReferenceMapping.java:373) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoWorkingCopyClone(ObjectBuilder.java:2007) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:2268) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:858) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:745) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:699) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:850) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:968) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:579) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1221) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:914) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1180) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:466) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1268) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:3020) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1892) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1874) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839) ~[org.eclipse.persistence.core-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:262) ~[org.eclipse.persistence.jpa-2.7.3-19-cuba.jar:na]
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:482) ~[org.eclipse.persistence.jpa-2.7.3-19-cuba.jar:na]
... 113 common frames omitted
С самой ошибкой всё понятно. В “кишках” EclipseLink есть такой код, который выполняется (как я понял) когда много JOINов и там возникает исключение.
List nestedDataResults = dataResults;
if (nestedDataResults == null) {
Object sourceKey = this.descriptor.getObjectBuilder().extractPrimaryKeyFromRow(row, executionSession);
nestedDataResults = joinManager.getDataResultsByPrimaryKey().get(sourceKey); // ТУТ в HashMap нет элемента с искомым ключём, поэтому nestedDataResults = null
}
nestedDataResults = new ArrayList(nestedDataResults); // ТУТ nestedDataResults = null и возникает исключение
И ошибка возникает только когда на экране используется фильтр. Вероятно опять это из-за LIMITa.
Сталкивался ли кто-то с такой проблемой и есть ли решение (помимо отказа от JOINов)?