List not iterable - mybatis

I have a problem with MyBatis,
I can't give names for variables and so on...
Confidential data, I prefer not to give :)
I have this error :
org.apache.ibatis.builder.BuilderException: Error evaluating expression '<liste_name>'. Return value ( <all values in list separated with comma here> ) was not iterable.
Java :
List<BigDecimal> <liste_name> = Stream.of(<one String variable>.split(",")).map(BigDecimal.new).collect(Collectors.toList());
BigDecimal <one_id> = [recuperation here of the id...]
Map<String, Object> map = new HashMap<>();
map.put("<liste_name>", <liste_name>);
map.put("<one_id>",<one id>);
return <call here SQL request>(map);
SQL
[begining of SQL request...]
WHERE <col number 1> = <one_id>
AND <col number 2> IN
<foreach open="(" separator="," close=")" collection="<liste_name>" item="<item_name>">
#{<item_name>}
</foreach>
[end of SQL request...]
Thank you very, very, very much to help me :)

Related

Thymeleaf select and CriteriaBuilder

It's a simple thing I want to do that somehow raises a complex issue.. I'm going insane over this...
I want to compare my Pages field using criteriabuilder; get all that are less than, so use 'le' for numbers ('lessThanOrEqualTo' doesn't work here ).
How can you send an Integer from a Thymeleaf select so that if it is not selected it won't be added to your search criteriaBuilder ?
In the select you're forced by thymeleaf to have a String "undefined" option as a first option. If I use Integer as the field type it won't bind this "undefined" option to the posted model where I would later filter it out from the criteriabuilder. The numbers are OK here though. I need it to work if not selected or undefined.
If I go the other way and choose a String field for Pages then it will not be parsed for ...
le(Expression x, Expression y)
in the CriteriaBuilder. I cannot turn
b.get("pages")
into
Expression<? extends Number> myInteger
I've tried everyway....
<select th:field="*{pages}" ng-model="bookData.pages">
<option selected="selected" value=""> select an option </option>
<option th:each="selectItem: ${refData.pages}"
th:value="${selectItem.value}"
th:text="${selectItem.label}">Pages</option>
</select>
List<Predicate> predList = new LinkedList<Predicate>();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Book> c =cb.createQuery(Book.class);
Root<Book> b = c.from(Book.class);
if( (!pages.equals("")) && (!pages.equals("undefined")) ){
predList.add(cb.lessThanOrEqualTo(b.get("pages"), pages));
}
How could you send an Integer from a Thymeleaf select to be compared in the query so that if not selected doesn't get added to the query?
Ahhhhhhh!
I found the solution by Checking my Angularjs from the form
$scope.processSearchForm = function() {
var aData = $scope.bookData.author;
var gData = $scope.bookData.genre;
var pData = $scope.bookData.pages;
if(typeof pData === 'undefined'){
pData='0';
}
and setting it to '0' if it didn't exist and therefore undefined/unselected.
I then went with Integer for the field, obviously the right approach.
It binds to the model and 0 is filtered out of the Query with the CriteriaBuilder.
Johnny O.

XML Mapper issue in Mybatis

nested exception is org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException: The content of elements must consist of well-formed character data or markup.
this is the syntax
it working well while fetching the result in ORACLE SQL DEVELOPER
but while start my local server it gives error
please suggest what need to fix on this
SQL is good and working to get records directly from DB
select
rownum test,
os_alternate_label "altlabel",
em_customs_bar_code "label",
em_source_appl "source",
'H5' "altoutcome",
DECODE(OS_NL_DO_NOT_LOAD,1,'NL',
DECODE(OS_H5_ALT_DUP_HOLD,1,'H5',
DECODE(OS_BD_RTS_EC,1,'BD',
DECODE(OS_H2_EC_HOLD,1,'H2',
DECODE(OS_HD_NO_DISP_HOLD,1,'HD',
DECODE(OS_H3_CBP_HOLD,1,'H3',
DECODE(OS_H4_USPIS_HOLD,1,'H4',
DECODE(OS_UD_RTS_CUSTOMER,1,'UD',
DECODE(OS_NQ_EU_WAIT_TIME,1,'NQ',
DECODE(OS_H1_iPASS_HOLD,1,'H1',
DECODE(OS_DG_DANGER_HOLD,1,'DG',
DECODE(OS_CC_COMM_HOLD,1,'CC',
DECODE(OS_H6_CUS_DUP_HOLD,1,'H6',
DECODE(OS_RL_RELEASE,1,'RL','XX')))))))))))))) "customoutcome",
em_destination_country "destCo",
em_recipient_last_name "tolastName",
em_recipient_business "tobusinessname",
em_recipient_address "toaddress",
em_recipient_city "tocity",
em_recipient_state "toregionprov",
em_recipient_postcode "postcode",
to_char(em_date_time_received,'MM/DD/YY HH24:MI') "timeReceived"
FROM CUSTOMS.OUTCOME_STATUS_T,
CUSTOMS.ECM_MANIFEST_T
WHERE OS_CUSTOMS_BAR_CODE = EM_CUSTOMS_BAR_CODE
Use escape character I believe the '/' used to define date is causing problem
<![CDATA[
select
rownum test,
os_alternate_label "altlabel",
em_customs_bar_code "label",
em_source_appl "source",
'H5' "altoutcome",
DECODE(OS_NL_DO_NOT_LOAD,1,'NL',
DECODE(OS_H5_ALT_DUP_HOLD,1,'H5',
DECODE(OS_BD_RTS_EC,1,'BD',
DECODE(OS_H2_EC_HOLD,1,'H2',
DECODE(OS_HD_NO_DISP_HOLD,1,'HD',
DECODE(OS_H3_CBP_HOLD,1,'H3',
DECODE(OS_H4_USPIS_HOLD,1,'H4',
DECODE(OS_UD_RTS_CUSTOMER,1,'UD',
DECODE(OS_NQ_EU_WAIT_TIME,1,'NQ',
DECODE(OS_H1_iPASS_HOLD,1,'H1',
DECODE(OS_DG_DANGER_HOLD,1,'DG',
DECODE(OS_CC_COMM_HOLD,1,'CC',
DECODE(OS_H6_CUS_DUP_HOLD,1,'H6',
DECODE(OS_RL_RELEASE,1,'RL','XX')))))))))))))) "customoutcome",
em_destination_country "destCo",
em_recipient_last_name "tolastName",
em_recipient_business "tobusinessname",
em_recipient_address "toaddress",
em_recipient_city "tocity",
em_recipient_state "toregionprov",
em_recipient_postcode "postcode",
to_char(em_date_time_received,'MM/DD/YY HH24:MI') "timeReceived"
FROM CUSTOMS.OUTCOME_STATUS_T,
CUSTOMS.ECM_MANIFEST_T
WHERE OS_CUSTOMS_BAR_CODE = EM_CUSTOMS_BAR_CODE
]]>

MyBatis batch update for oracle

I am trying to do the batch update in myBatis with oracle Database, where i have to update 10K+ records.
But when i use below
I am getting exception says 'invalid character'.
It is working fine when i do single update statement multiple times.
Please help with your example if you already tried this.
<update id="batchUpdate">
<foreach collection="empList" item="employee" separator=";">
UPDATE Employee
SET EMP_JOBTITLE = #{employee.jobTitle},
EMP_STATUS = #{employee.status}
WHERE Employee_ID = #{employee.empId}
</foreach>
</update>
If you use Oracle:
<update id="batchUpdate">
call
begin
<foreach collection="empList" item="employee" close=";" eparator=";">
UPDATE Employee
SET EMP_JOBTITLE = #{employee.jobTitle},
EMP_STATUS = #{employee.status}
WHERE Employee_ID = #{employee.empId}
</foreach>
end
</update>
I was not able to resolve that error, but came across this post in which a code contributor recommended that the proper way to batch update is to open a session in batch mode and repeatedly call update for a single record.
Here's what works for me:
public void updateRecords(final List<GisObject> objectsToUpdate) {
final SqlSession sqlSession = MyBatisUtils.getSqlSessionFactory().openSession(ExecutorType.BATCH);
try {
final GisObjectMapper mapper = sqlSession.getMapper(GisObjectMapper.class);
for (final GisObject gisObject : objectsToUpdate) {
mapper.updateRecord(gisObject);
}
sqlSession.commit();
} finally {
sqlSession.close();
}
}
Then, remove the foreach in your update and modify it to update a single record (remove the "employee.")

How to declare dynamic form field defaults inside a Coldfusion CFC?

I'm looking for a way to declare form default values dynamically in a CFC, I'm calling via AJAX. The current CFC sends orders, which I need to break down into sub-orders.
I had been using this:
<!--- static defaults --->
<cffunction name="Defaults" access="public" returntype="struct" output="false"
hint="Assign default values to instance">
<cfscript>
var formDefaults = {
versenden=""
, speichern=""
...
}
</cfscript>
<cfreturn formDefaults />
</cffunction>
<cffunction name="Commit" access="public" returntype="struct" output="false" hint="database handler">
<!--- add dynamic form fields --->
<cfscript>
var LOCAL = {};
variables.defs = THIS.Defaults();
</cfscript>
<cfloop collection="#VARIABLES.Instance.FormData#" item="formField">
<cfscript>
if ( LEFT(formField, 5) EQ "MENGE"
OR LEFT(formField, 3) EQ "EAN"
OR LEFT(formField, 12) EQ "BESTELL_TEXT"
OR LEFT(formField, 10) EQ "BESTELLTYP"
...
) {
variables.defs[formField]="";
}
</cfscript>
</cfloop>
<cfscript>
structAppend(variables.defs, VARIABLES.Instance.FormData);
LOCAL.Basket = variables.defs;
</cfscript>
...
So I first declare static form fields (single instance only) and then try to dynamically append dynamic form fields to my array, which might be transferred multiple times (MENGE38, MENGE39, MENGE40 etc)
While this works ok, I need to add another counting element to my form-names, so I would have to change MENGE to something like counter.MENGE or MENGE.counter which will then send form values like this:
MENGE.1.38
MENGE.1.40
MENGE.1.41
MENGE.2.37
With the counter denoting the sub-order, this field is used for.
Problem is, this breaks my dynamic form field declaration and I don't understand why. I'm getting the following errors:
Diagnose: Element MENGE.1 is undefined in a CFML structure referenced as part of an expression.
Question:
Can anyone give me a hint on what the problem might be? Do I have to param the form fields on the HTML page as well (shouldn't have to)?
Thanks!
EDIT:
Problem was in my validate function, I also need to declare the modifications I did above. The new function looks like this:
<cffunction name="Validate" access="public" returntype="array" output="false" hint="validate form inputs and return an array of faulty field names.">
<cfscript>
var LOCAL = {};
var double = structNew();
double.form = VARIABLES.Instance.FormData;
double.criteria = VARIABLES.Instance.Validation;
</cfscript>
<!--- add dynamic form fields for validation... I FORGOT TO UPDATE THIS--->
<cfloop collection="#VARIABLES.Instance.FormData#" item="formField">
<cfscript>
if ( LEFT(formField, 5) EQ "MENGE"
OR LEFT(formField, 10) EQ 'BESTELLTYP'
OR LEFT(formField, 3) EQ "EAN"
OR LEFT(formField, 12) EQ "BESTELL_TEXT"
...
) {
VARIABLES.Instance.Validation[formField]="pass";
}
</cfscript>
</cfloop>
<!--- Get error names and type --->
<cfinvoke component="form_validate" method="validate_fields" double="#double#" returnvariable="validation_errors"></cfinvoke>
<cfset LOCAL.ErrorMessages = validation_errors />
<cfreturn LOCAL.ErrorMessages />
Because I did not add the new updated the if-clause in this function, I was getting the error.
To build on Dan Bracuk's answer, use underscores (though you'd need to change the name of "BESTELL_TEXT"). Use this with a combination of listFirst, listGetAt, and listLast to determine field name structure, using underscore as delimiter. Note how I cleaned up your big IF a bit using list function. This code as written probably doesn't do what you need, but wanted to illustrate the concepts without having to understand your business need.
<cfscript>
var orders=structNew();
item=listFirst(formField,'_');
orderNames = "MENGE,EAN,BESTELLTEXT,BESTELLTYPE";
if (listFindNoCase(orderNames,item,'_')){
if (!structKeyExists(orders,item)){
// initialize item
orders[item]=structNew();
}
orderID="";
subOrderId="";
if (listLen(formField,'_') gt 1) {
orderID=listGetAt(formField,2,'_');
}
if (listLen(formField,'_') eq 2) {
orders[item][orderId]=formData[formField];
}
if (listLen(formField,'_') eq 3) {
subOrderId=listLast(formField,'_');
orders[item][orderId][subOrderId]=formData[formField];
}
}
</cfscript>

Parsing an XML string containing " " (which must be preserved)

I have code that is passed a string containing XML. This XML may contain one or more instances of (an entity reference for the blank space character). I have a requirement that these references should not be resolved (i.e. they should not be replaced with an actual space character).
Is there any way for me to achieve this?
Basically, given a string containing the XML:
<pattern value="[A-Z0-9 ]" />
I do not want it to be converted to:
<pattern value="[A-Z0-9 ]" />
(What I am actually trying to achieve is to simply take an XML string and write it to a "pretty-printed" file. This is having the side-effect of resolving occurrences of in the string to a single space character, which need to be preserved. The reason for this requirement is that the written XML document must conform to an externally-defined specification.)
I have tried creating a sub-class of XmlTextReader to read from the XML string and overriding the ResolveEntity() method, but this isn't called. I have also tried assigning a custom XmlResolver.
I have also tried, as suggested, to "double encode". Unfortunately, this has not had the desired effect, as the & is not decoded by the parser. Here is the code I used:
string schemaText = #"...<pattern value=""[A-Z0-9&#x20;]"" />...";
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
writerSettings.NewLineChars = Environment.NewLine;
writerSettings.Encoding = Encoding.Unicode;
writerSettings.CloseOutput = true;
writerSettings.OmitXmlDeclaration = false;
writerSettings.IndentChars = "\t";
StringBuilder writtenSchema = new StringBuilder();
using ( StringReader sr = new StringReader( schemaText ) )
using ( XmlReader reader = XmlReader.Create( sr ) )
using ( TextWriter tr = new StringWriter( writtenSchema ) )
using ( XmlWriter writer = XmlWriter.Create( tr, writerSettings ) )
{
XPathDocument doc = new XPathDocument( reader );
XPathNavigator nav = doc.CreateNavigator();
nav.WriteSubtree( writer );
}
The written XML ends up with:
<pattern value="[A-Z0-9&#x20;]" />
If you want it to be preserved, you need to double-encode it: &#x20;. The XML-reader will translate entities, that's more or less how XML works.
<pattern value="[A-Z0-9&#x20;]" />
What I did above is replaced "&" with "&" thereby escaping the ampersand.