Spring Data JPA不适用于CascaseType.PERSIST和@OneToOne

时间:2015-12-21 16:47:42

标签: java hibernate jpa spring-data spring-data-jpa

我使用Spring Data JPA为一个小项目列出一些信息。我有一个LogEntry类,它代表我GUI上网格中的一行。其他类用于添加/显示更详细的Informationen,例如上载/下载文件的功能。我将文件数据和元信息分成两个类/表。我的班级关系如下:LogEntry - > Comment - > FileReference - > FileData

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;
    }
}

通过这种分离,我可以在不加载db中的每个文件的情况下读取所有LogEntry,但我仍然能够显示文件的元信息并提供下载它的方法。我在每个关系上使用CascadeType.ALL。这非常有效,直到我尝试更改已存在的Comment中的某些数据。该应用程序尝试将FileReference保存为FileData,但不允许使用FileReference。然后我尝试将关系FileData - &gt; CascadeType.PERSIST更改为Comment,但当我尝试保存CascadeType.MERGE

时会导致异常
  

org.springframework.orm.jpa.JpaObjectRetrievalFailureException:无法找到ID为123的..FileData;嵌套异常是javax.persistence.EntityNotFoundException:无法找到具有id PersistentStringObjectKey的..FileData 123

似乎spring数据无法处理没有CascadeType.ALL的情况。我想到的唯一两个解决方案是,我使用Comment,当我需要更改和更新FileData时,我为所有FileReferences加载Comment,然后保存{{ 1}}或者我不使用CascadeType.ALL并在存储“main”对象之前创建一个DAO,其中我保存每个对象的每个引用。但这根本不好。

问题: 有没有人知道如何使用CasecadeType正确的方法来实现我的目标,不在每个选择上加载FileData而不是在将更改保存到其他实体之前预加载它?

1 个答案:

答案 0 :(得分:1)

因为java BLOB插入BD需要插入和更新而不是仅插入,因此需要cascade={CascadeType.PERSIST,CascadeType.MERGE}