Issue
I'm trying to iterate an input field thru GET in Java Controller and thymeleaf but it's giving me the error of "result returns more than one elements"
My GET can receive the Array of String ID's but I can't put them in my Form, I will use my Form to POST it and delete the Array of String ID's. It's working if the user input is only one but when the user input becomes 2 or more it shows the error "result returns more than one elements"
This is my code on Java Controller
@RequestMapping(value="/delete-asset", method = RequestMethod.GET)
public String deleteAsset(@RequestParam String[] assetID, Model model) {
//to populate the form
model.addAttribute("DeleteCategoryObject", assetService.getAssetInfo(assetID));
return "delete-asset";
}
This is my code on Html Form
<form method="POST" name="deleteFormAdd" id="deleteFormAdd" th:object="${DeleteCategoryObject}"enctype="multipart/form-data">
<input type="hidden" name="_csrf" th:value="${_csrf.token}" />
//The code can't iterate the String of array given by the GET
<input type="hidden" th:field="*{assetID}" />
//This button is for submitting the String of array ID to be deleted
<input type="button" class="btn btn-primary btn-block" value="Yes" th:onclick="'javascript:submitForm(\'deleteFormAdd\',\''+@{/delete-asset}+'\')'" />
<button type="reset" onclick="window.location.href = 'manage-assets.html';" class="btn btn-default btn-block"> Cancel</button>
</form>
The code can accept this link
But it shows the error "result returns more than one elements" When the given ID is 2 or more
Full Error
org.springframework.dao.IncorrectResultSizeDataAccessException: result returns more than one elements; nested exception is javax.persistence.NonUniqueResultException: result returns more than one elements
Java DAO/Query
@Query("From AssetCategory A WHERE A.assetID IN (:assetID)")
public AssetCategory getAssetInfo(@Param("assetID") String[] assetID);
AssetCategory
@Entity
@Table(name = "ASSET_TYPE")
public class AssetCategory implements Serializable{
private static final long serialVersionUID = 595169758417136780L;
@Id
@Column(name = "ASSET_ID")
@GenericGenerator(name="uuid", strategy="uuid")
@GeneratedValue(generator="uuid")
private String assetID;
@Column(name = "ASSET_TYPE")
private String assetType;
@Column(name = "CATEGORY")
private String category;
@Column(name = "DESCRIPTION")
private String description;
@Column(name = "CREATED_BY")
private String createdBy;
public AssetCategory() {
super();
public AssetCategory(String assetID, String assetType, String category, String description, String createdBy) {
super();
this.assetID = assetID;
this.assetType = assetType;
this.category = category;
this.description = description;
this.createdBy = createdBy;
}
//getters setters below
public String getAssetID() {
return assetID;
}
public void setAssetID(String assetID) {
this.assetID = assetID;
}
public String getAssetType() {
return assetType;
}
public void setAssetType(String assetType) {
this.assetType = assetType;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
Controller for Java Delete Post
@RequestMapping(value = "/delete-asset", method = RequestMethod.POST)
public @ResponseBody String deleteAsset(@ModelAttribute AssetCategory assetCategory) {
JsonObject result = new JsonObject();
assetService.deleteAssets(assetCategory.getAssetID());
result.addProperty("result", "Success");
result.addProperty("status", 1);
result.addProperty("message", "Asset Deleted!");
return result.toString();
}
Query of Delete POST
@Query("Delete From AssetCategory A WHERE A.assetID IN (:assetID)")
List<AssetCategory> deleteAssets(@Param("assetID") String[] assetID);
Delete POST Service
@Override
public List <AssetCategory> deleteAssets(String[] assetID) {
return dao.deleteAssets(assetID);
}
Submit Form function
function submitForm(formID, url){
var formData = new FormData($("#" + formID)[0]);
$.ajax({
dataType: 'json',
url: url,
data : formData,
type : "POST",
enctype : "multipart/form-data" ,
processData : false,
contentType : false,
success : function(data) {
if (data.status == 1) {
openAlertDialog("Success", "The Asset type has been deleted!", "Continue", "manage-assets");
} else {
openAlertDialog("Error", data.message, "Continue", "manage-assets");
}
},
error : function(data) {
openAlertDialog("Error", data.message, "Continue", "manage-assets");
},
});
}
Solution
Problem is with your query. When you provide array of assetID
Query trying to return List of AssetCategory
objects. But currently method allows to return only one AssetCategory
object. That's why the error comes when you pass array of assetID
. So you have to change the return type of getAssetInfo
method as below:
@Query("From AssetCategory A WHERE A.assetID IN (:assetID)")
public List<AssetCategory> getAssetInfo(@Param("assetID") String[] assetID);
Now getAssetInfo
method returns List of AssetCategory
objects. Which means you are now passing List<AssetCategory>
to DeleteCategoryObject
model attribute. So you have to do necessary changes in your front end.
You can now iterate it in front end as below:
<form method="POST" name="deleteFormAdd" id="deleteFormAdd" enctype="multipart/form-data">
<input type="hidden" name="_csrf" th:value="${_csrf.token}" />
//The code can't iterate the String of array given by the GET
<input type="hidden" class="assetId" th:each="deleteCategory, itemStat : ${DeleteCategoryObject}" th:name="|DeleteCategoryObject[__${itemStat.index}__].assetID|" th:value="${deleteCategory.assetID}"/>
//This button is for submitting the String of array ID to be deleted
<input type="button" class="btn btn-primary btn-block" value="Yes" th:onclick="'javascript:submitForm(\'deleteFormAdd\',\''+@{/delete-asset}+'\')'" />
<button type="reset" onclick="window.location.href = 'manage-assets.html';" class="btn btn-default btn-block"> Cancel</button>
</form>
Change the Post controller as below:
@RequestMapping(value = "/delete-asset", method = RequestMethod.POST)
public @ResponseBody String deleteAsset(@ModelAttribute List<AssetCategory> assetCategories) {
JsonObject result = new JsonObject();
if (assetCategories != null && !assetCategories.isEmpty()) {
String[] arr = new String[assetCategories.size()];
for (int i =0; i < assetCategories.size(); i++) {
arr[i] = assetCategories.get(i).getAssetID();
}
assetService.deleteAssets(arr);
result.addProperty("result", "Success");
result.addProperty("status", 1);
result.addProperty("message", "Asset Deleted!");
}
return result.toString();
}
Submit form function:
function submitForm(formID, url) {
var assetIdList = [];
var assetIdObj;
$("#" + formID).find('.assetId').each(function () {
assetIdObj = {};
assetIdObj.assetID = $(this).val();
assetIdList.push(assetIdObj);
});
$.ajax({
dataType: 'json',
url: url,
data: {assetCategories: assetIdList},
type: "POST",
enctype: "multipart/form-data",
processData: false,
contentType: false,
success: function (data) {
if (data.status === 1) {
openAlertDialog("Success", "The Asset type has been deleted!", "Continue", "manage-assets");
} else {
openAlertDialog("Error", data.message, "Continue", "manage-assets");
}
},
error: function (data) {
openAlertDialog("Error", data.message, "Continue", "manage-assets");
},
});
}
Answered By - Anuradha
Answer Checked By - Willingham (JavaFixing Volunteer)