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