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


通过这种分离,我可以读取所有LogEntry而不从数据库中加载每个文件,但是我仍然能够显示文件的元信息并提供下载方法。我在每个关系上都使用CascadeType.ALL。这非常有效,直到我尝试更改已经存在的Comment中的某些数据。该应用程序试图保存一个FileReference,其中没有对FileData的空引用。然后我尝试将关系FileReference-> FileData更改为CascadeType.PERSIST,但是当我尝试保存Comment时,这会导致异常


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


如果没有CascadeType.MERGE,似乎spring数据无法处理。我要记住的唯一两个解决方案是,我使用CascadeType.ALL,并且当我必须更改和更新Comment时,我为所有FileData加载FileReferences,然后保存Comment,否则我不使用CascadeType .ALL并创建一个DAO,在存储“主”对象之前,我在其中保存了每个对象的每个引用。但这根本不好。

题:
有谁知道如何使用CasecadeType的正确方法来实现我的目标,即不要在每次选择时都加载FileData并在将更改保存到其他实体之前不对其进行预加载?

最佳答案

由于Java将BLOB插入BD中需要插入和更新而不是仅插入和更新,因此需要cascade={CascadeType.PERSIST,CascadeType.MERGE}

10-04 14:13