我有一个小批量上传工作,我正在迭代抛出一个CSV文件并创建对象并使用grails gorm保存它们。如果csv文件中的记录有任何失败,我会跳过记录并继续下一步。我发现如果没有使用withNewTransaction将我的保存包装在新的事务中,我无法保存任何对象。我认为这是解决实际问题的黑客行为。我想知道是否有人能够帮助我理解这里发生的事情。
控制器
dim emailreceiver as string
emailreceiver = '(the new object I created that called the function, in this case it is "assignmsg").msgto
BatchUploadService
def uploadFile() {
def division = params.division;
userService.requireRole(division)
MultipartFile file = request.getFile('file');
if(file.empty) {
flash.message = "File cannot be empty"
} else {
def effortDetailMap = batchUploadService.processBatch(file, division);
flash.success = effortDetailMap['Success'].size() + " new records were successfully added.";
flash.failed = effortDetailMap['Failed'].size() + " records failed to be added.";
flash.filtered = effortDetailMap['Filtered'].size() + " records were filtered.";
batchUploadService.excelOutput(effortDetailMap);
}
redirect (action:'upload', params: [division: params.division])
}
RecoveryDetailService
def populateBean(file) {
CsvToBean<EffortDetail> csvToBean = new CsvToBean<>();
Map<String, String> columnMapping = new HashMap<String, String>();
columnMapping.put("ITEM_NO", "alternateId");
columnMapping.put("FIRST_NAME", "firstName");
columnMapping.put("LAST_NAME", "lastName");
columnMapping.put("TASK_CODE", "orgkey");
columnMapping.put("PAY_END_DATE", "expenseDate");
columnMapping.put("TOT_TDS_TIME", "projectHours");
columnMapping.put("411 TOTAL", "totalHours");
HeaderColumnNameTranslateMappingStrategy<EffortDetail> strategy = new HeaderColumnNameTranslateMappingStrategy<EffortDetail>();
strategy.setType(EffortDetail.class);
strategy.setColumnMapping(columnMapping);
Reader reader = new InputStreamReader(file.getInputStream());
CustomReader csvReader = new CustomReader(reader, (char) '|', CSVWriter.NO_QUOTE_CHARACTER);
return csvToBean.parse(strategy, csvReader);
}
def processBatch(file, division) {
def effortDetails = populateBean(file)
def effortDetailMap = [:]
effortDetailMap["Success"] = []
effortDetailMap["Failed"] = []
effortDetailMap["Filtered"] = []
for (def effortDetail in effortDetails) {
String orgKey = effortDetail.getOrgkey();
if (orgKey.matches("\\d{6}") || orgKey.matches("\\d{6} HRI")) {
effortDetail.setOrgkey(orgKey.substring(0, 6));
} else {
effortDetailMap['Filtered'] << effortDetail;
continue;
}
effortDetail.setDivision(division)
effortDetail.setPkDivision(effortDetail.getDivision());
effortDetail.setPkOrgkey(effortDetail.getOrgkey());
try {
if(effortDetail.getTotalHours() == null || effortDetail.getTotalHours().isEmpty()) {
throw new NullPointerException("Invalid Total Hours");
} else if(new BigDecimal(effortDetail.getTotalHours()).compareTo(new BigDecimal(75)) < 0) {
effortDetail.setTotalHours("75");
}
if(effortDetail.getProjectHours() == null || effortDetail.getProjectHours().isEmpty()) {
throw new NullPointerException("Invalid Project Hours");
}
RecoveryDetail recoveryDetail = recoveryDetailService.fill(effortDetail);
if(!recoveryDetail.validate()) {
def errors = new StringBuilder()
recoveryDetail.errors.each {errors.append(it)}
throw new Exception(errors);
}
RecoveryDetail.withNewTransaction {TransactionStatus status ->
try {
recoveryDetail.save(failOnError: true)
} catch (ex) {
status.setRollbackOnly()
}
}
effortDetailMap['Success'] << effortDetail
} catch(Exception ex) {
effortDetail.failure = ex.message;
effortDetailMap['Failed'] << effortDetail
}
}
return effortDetailMap
}