Я использую Spring Data JPA для небольшого проекта, чтобы перечислить некоторую информацию. У меня есть класс LogEntry, который представляет одну строку в сетке моего графического интерфейса. Другие классы используются для добавления/отображения более подробной информации, например, для загрузки/загрузки файла. Я разделил данные файла и метаинформацию на два класса/таблицы. Отношения моих классов выглядит следующим образом: LogEntry
->Comment
->FileReference
->FileData
Spring Data JPA не работает с CascaseType.PERSIST и @OneToOne
FileReference.java
@Entity
public class FileReference extends AbstractEntity {
private static final long serialVersionUID = 3942449578983368585L;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
private FileData fileData;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private int size;
}
FileData.java
@Entity
public class FileData extends AbstractEntity {
private static final long serialVersionUID = 6706563782575452010L;
@Lob
byte[] byteArray;
}
LogEntryRepo.java
public interface LogEntryRepo<LogEntry> extends JpaRepository<LogEntry, ObjectKey> {
}
Моего лицо
@Component
@Transactional(readOnly = true)
public class LogEntryServiceImpl implements LogEntryService {
@Autowired
LogEntryRepo repo;
@Autowired
FileReferenceRepo fileReferenceRepo;
/**
* save a changed LogEntry
*/
@Override
@Secured(Roles.ROLE_WRITE)
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void saveLogEntry(LogEntry logEntry) {
if (logEntry != null) {
LogEntry one = repo.getOne(logEntry.getObjectKey());
if (one != null) {
if (one.isAudited()) {
throw new AlreadyAuditedException();
}
}
}
repo.save(logEntry);
}
@Override
@Secured(Roles.ROLE_READ_ONLY)
@Transactional(readOnly = true)
public List<LogEntry> loadAll() {
List<LogEntry> findAll = repo.findAll();
for (LogEntry logEntry : findAll) {
setNullForFileData(logEntry); // avoid serialization problems with lazy loading proxies
}
return findAll;
}
@Override
@Secured(Roles.ROLE_READ_ONLY)
@Transactional(readOnly = true)
public FileReference loadFileData(ObjectKey key) {
FileReference fileReference = fileReferenceRepo.findOne(key);
// fileData ist lazy loaded. call once to load it from db.
fileReference.getFileData().getObjectKey();
return fileReference;
}
}
С помощью этого разделения я могу просто прочитать все LogEntry
сек без загрузки каждого отдельного файла из БДА, но я до сих пор в состоянии показать метаинформацию файла и обеспечить способ его загрузки. Я использую CascadeType.ALL для каждого отношения. Это работало очень хорошо, пока я не попытался изменить некоторые данные в уже существующем Comment
. Приложение попыталось сохранить FileReference
с нулевой ссылкой на FileData
, что запрещено. Затем я попытался изменить отношение FileReference
->FileData
к CascadeType.PERSIST
, но это приводит к исключению, когда я пытаюсь сохранить Comment
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Не удалось найти ..FileData с идентификатором 123; вложенное исключение javax.persistence.EntityNotFoundException: Не удается найти ..FileData с идентификатором PersistentStringObjectKey 123
Кажется, что весной данные не могут справиться с этим без CascadeType.MERGE
. Единственные два решения, которые я имею в виду, это то, что я использую CascadeType.ALL
, и когда мне нужно изменить и обновить Comment
Загрузите FileData
для всех FileReferences
, а затем сохраните Comment
или я не использую CascadeType.ALL и сделаю DAO, в котором я сохраняю каждой ссылки каждого объекта, прежде чем хранить «основной» объект. Но это совсем не приятно.
Вопрос: Кто-нибудь знает, как использовать CasecadeType
сек правильный путь для достижения своих целей, чтобы не загружать FileData
на каждый выбор и не поджать его перед сохранением изменений в других организациях?
Прежде всего, весна не имеет значения. Ваш JPA-провайдер - это Hibernate, а не Spring. Во-вторых, проблема заключается в коде, и вы не публиковали его. Чтобы получить ссылку на существующую FileData без ее загрузки, просто используйте 'EntityManager.getReference()' (или 'JpaRepository.getOne()') –
Я использую данные весны jpa, поэтому я не использую JPA напрямую. https: // GitHub.com/spring-projects/spring-data-jpa-examples/blob/master/spring-data-jpa-example/src/main/java/org/springframework/data/jpa/example/repository/custom/UserRepository.java I Изменим вопрос и код, как я получаю доступ к своим сущностям. Я хочу получить список 'LogEntry', а не одну' FileData' без загрузки – lrxw
Да, поэтому мой совет по использованию JpaRepository.getOne(). JpaRepository - это класс из Spring-data-jpa. –