2015-12-21 57 views
1

我使用Spring Data JPA爲一個小項目列出一些信息。我有一個類LogEntry,它表示我的GUI上的一個網格中的一行。其他類用於添加/顯示更詳細的信息,如上傳/下載文件的能力。我將文件數據和元信息分隔到兩個類/表中。我的課的關係是這樣的: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 - >FileDataCascadeType.PERSIST,但這會導致一個異常時,我嘗試保存Comment

org.springframework.orm.jpa.JpaObjectRetrievalFailureException:無法找到..FileData與ID 123;嵌套的例外是javax.persistence.EntityNotFoundException:無法找到..FileData ID爲PersistentStringObjectKey 123

似乎春天的數據不能處理,沒有CascadeType.MERGE。我想到的唯一兩個解決方案是,我使用CascadeType.ALL,當我必須更改和更新Comment我加載FileData所有FileReferences,然後保存Comment或者我沒有使用CascadeType.ALL並創建一個DAO,我在其中保存在存儲「主」對象之前,每個對象的每個引用。但這根本不好。

問題: 有誰知道如何使用CasecadeType S上的正確的方式來實現自己的目標不加載每個選擇FileData,而不是更改保存到其他實體之前預裝了嗎?

+0

首先,Spring是無關緊要的。你的JPA提供者是Hibernate,而不是Spring。其次,問題在於代碼,而您沒有發佈它。要獲得對現有FileData的引用而不加載它,只需使用'EntityManager.getReference()'(或'JpaRepository.getOne()') –

+0

我使用彈簧數據jpa,所以我不直接使用JPA。 https://開頭github上。/ 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插入BLOBBD需要插入和更新而不是隻插入,所以需要cascade={CascadeType.PERSIST,CascadeType.MERGE}