У меня очень странная проблема с JPA, и я надеюсь получить подсказки, как ее решить. Я использую новейший сервер Payara Full с Eclipselink и новейшую PostgreSQL -database.
У меня простое двунаправленное отношение «многие ко многим». В EJB-транзакции я создаю объект-компанию, сохраняю его (entityManager.persist ()), создаю сотрудника, устанавливаю объект-компанию и persist (), затем добавляю сотрудника в коллекцию в объекте-компании и вызовите entitymanager.merge () ... все внутри одной транзакции (метод Stateless-EJB-publi c). => отношение смоделировано после подсказок Vlads (используйте наборы вместо списков и т. д.).
Теперь в другой транзакции я меняю сотрудника, сливаю () изменения и изменения обновляются в база данных. Таким образом, с точки зрения базы данных все в порядке (даже поле @Version обновляется соответствующим образом).
Но теперь, если я удаляю компанию, она удаляется из базы данных успешно, но в памяти , компания все еще там. И это становится еще более странным: даже если я назову refre sh для сотрудника, компания все еще будет указана в объекте, даже если его больше нет в базе данных.
Если я отмечу компанию и сотрудник как @Cachable (value = false), все работает нормально. Даже если вместо обновления сотрудника я вызову entityManager.getEntityManagerFactory (). GetCache (). EvictAll (), он также удаляет компанию из объекта empployee.
Возможно, проблема в структуре наследования ? Я очень озадачен тем, что вызов entityManager.refre sh (employee); не извлекает свежее / текущее состояние из базы данных.
И это не имеет значения, если я изменяю сторону связи (уже проверено).
И равно () / hashCode также реализован (без коллекций, в противном случае он будет создавать круги), но упоминаются простые свойства, чтобы можно было / можно было распознать изменения в другой транзакции.
Итак, кто-то может дать мне несколько подсказок, где искать ошибку? Отключение кэша или удаление кэша - это скорее взлом, чем решение; -).
Заранее большое спасибо ...
@MappedSuperclass
public abstract class PersistEntity implements Serializable {
public static final String PROPERTY_NAME_ID = "_id";
@Id
@Column(name = "_id", length = 60)
@Convert(converter = ObjectIdAttributeConverter.class)
private ObjectId id;
@Version
@Column(name = "version")
private Long version;
// more simple properties
}
@MappedSuperclass
public abstract class PersistentExtEntity extends PersistentEntity {
// only simple string properties
}
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BusElementEntity extends PersistentExternalEntity {
// only simple string properties
}
@Entity
public class Company extends BusinessElementEntity {
@OneToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER)
private Employee leader;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE,
CascadeType.REFRESH
}, fetch = FetchType.LAZY)
@JoinTable(name = "employee_company",
joinColumns = @JoinColumn(name = "emp_id"),
inverseJoinColumns = @JoinColumn(name = "comp_id")
)
private Set<User> employees = new HashSet<>();
// ...
}
@Entity
public class Employee extends PersistentExtEntity {
@ManyToMany(mappedBy = "emplyoees", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private Set<Company> companies = new HashSet<>();
// ...
}
@Stateless
public class CompanyRepository {
@Inject
EntityManager entityManager;
public void createWithLeader(CreateCompanyRerquest request) {
Employee leader = employeeRepository.create(request); // creates the emplyoee object and calls "persist()"
Company company = new Company(request);
company.setLeader(emplyoee);
company.addEmplyoee(company.getLeader());
company.getLeader().getCompanies().add(company);
company.prePersist(); // this is an known eclipse bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=445272)
entityManager.persist(company);
entityManager.merge(company.getLeader());
}
public void deleteCompany(String externalCompanyId) {
final Optional<Company> companyOptional = getByExternalId(externalCompanyId);
Company dbCompany = companyOptional.orElseThrow(() -> new APIException(GlobalApiErrorCode.E4040001));
// entityManager.refresh(dbCompany); // contains still the very old employee object
dbCompany.getLeader().getCompanies().remove(dbCompany);
entityManager.merge(dbCompany.getLeader());
entityManager.remove(dbCompany);
}