2015-12-21 10 views
1

Я использую Spring Data JPA для небольшого проекта, чтобы перечислить некоторую информацию. У меня есть класс LogEntry, который представляет одну строку в сетке моего графического интерфейса. Другие классы используются для добавления/отображения более подробной информации, например, для загрузки/загрузки файла. Я разделил данные файла и метаинформацию на два класса/таблицы. Отношения моих классов выглядит следующим образом: LogEntry ->Comment ->FileReference ->FileDataSpring 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 на каждый выбор и не поджать его перед сохранением изменений в других организациях?

+0

Прежде всего, весна не имеет значения. Ваш JPA-провайдер - это Hibernate, а не Spring. Во-вторых, проблема заключается в коде, и вы не публиковали его. Чтобы получить ссылку на существующую FileData без ее загрузки, просто используйте 'EntityManager.getReference()' (или 'JpaRepository.getOne()') –

+0

Я использую данные весны 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

+0

Да, поэтому мой совет по использованию JpaRepository.getOne(). JpaRepository - это класс из Spring-data-jpa. –

ответ

0

Потому что вставка java BLOB в BD необходимо вставить и обновить, а не только вставить, поэтому требуется cascade={CascadeType.PERSIST,CascadeType.MERGE}.

Смежные вопросы