MyBatis, nested results for collection is empty - collections

I'm following the example in the MyBatis website to create a mapper that has a nested collection, when I do a select operation my object (Provider) is return but the collection inside it (ProviderParameter) is empty, when I go to the database tool and apply the same query I get the expected result (the collection is return too).
Here is my mapper:
<resultMap id="Provider" type="xxx.Provider">
<result column="idProvider" property="idProvider"/>
<result column="providerType" property="providerType"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="licenceInformation" property="licenseInformation"/>
<collection property="parameters" ofType="xxx.ProviderParameter">
<result column="idProviderParameter" property="idProviderParameter"/>
<result column="name" property="name"/>
<result column="value" property="value"/>
</collection>
</resultMap>
And the select:
<select id="getProviderById" resultType="xxx.Provider">
select P.idProvider as idProvider
,P.providerType as providerType
,P.username as username
,P.password as password
,P.licenceInformation as licenceInformation
,PP.idProviderParameter as idProviderParameter
,PP.name as name
,PP.value as value
from [dbo].[msg_Provider] AS P
left outer join [dbo].[msg_ProviderParameter] AS PP on P.idProvider = PP.idProvider
where P.idProvider = #{idProvider}
</select>

My problem was that in the select I put resultType instead of resultMap,
So the select should be like:
<select id="getProviderById" resultMap="Provider">
select P.idProvider as idProvider
,P.providerType as providerType
,P.username as username
,P.password as password
,P.licenceInformation as licenceInformation
,PP.idProviderParameter as idProviderParameter
,PP.name as name
,PP.value as value
from [dbo].[msg_Provider] AS P
left outer join [dbo].[msg_ProviderParameter] AS PP on P.idProvider = PP.idProvider
where P.idProvider = #{idProvider}
</select>

Related

SQLite + Mybatis-guice throw ArrayIndexOutOfBoundsException

I'm trying to implement a Guice module that to lets Guacamole use SQLite as a backend. The Guacamole project has a generic JDBC base module. This lets you implement modules for specific datastores with less code. Most of the lines of code end up being in mapper XML files. The project provides PostgreSQL and MySQL implementations.
I based this SQLite module off of the MySQL module. For the mapper XML files, SQLite and MySQL are similar enough that I didn't have to make any changes. However, when I try to use the SQLite module, I get this error:
### Error querying database. Cause: java.lang.ArrayIndexOutOfBoundsException: 2
### The error may exist in org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT guacamole_connection_group.connection_group_id, connection_group_name, parent_id, type, max_connections, max_connections_per_user, enable_session_affinity FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE guacamole_connection_group.connection_group_id IN ( ? ) AND user_id = ? AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE parent_id IN ( ? ) AND user_id = ? AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id FROM guacamole_connection JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id WHERE parent_id IN ( ? ) AND user_id = ? AND permission = 'READ';
### Cause: java.lang.ArrayIndexOutOfBoundsException: 2
It looks like the problem is that two parameters are passed to the query, but each is repeated three times. When MyBatis generates the PreparedStatement, it acts as if there are six parameters that needed to be passed in.
Here's the query it has a problem with:
<!-- Select multiple connection groups by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
SELECT
guacamole_connection_group.connection_group_id,
connection_group_name,
parent_id,
type,
max_connections,
max_connections_per_user,
enable_session_affinity
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE guacamole_connection_group.connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT parent_id, guacamole_connection_group.connection_group_id
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE parent_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT parent_id, guacamole_connection.connection_id
FROM guacamole_connection
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
WHERE parent_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
If I manually populate the parameters, I can execute this against the SQLite database. Also, the MySQL version works fine.
What the heck is going on? What can I do to debug this? Is it a MyBatis problem or something with the JDBC connector?
If it helps, you can see the code for the module here.
Here's the method for the parameter the mapper related to this query. The full mapper classes for ConnectionGroup are here and here. The full mapper XML for my SQLite module is here.
Collection<ModelType> selectReadable(#Param("user") UserModel user,
#Param("identifiers") Collection<String> identifiers);
This is what the ConnectionGroupResultMap looks like:
<resultMap id="ConnectionGroupResultMap" type="org.apache.guacamole.auth.jdbc.connectiongroup.ConnectionGroupModel" >
<!-- Connection group properties -->
<id column="connection_group_id" property="objectID" jdbcType="INTEGER"/>
<result column="connection_group_name" property="name" jdbcType="VARCHAR"/>
<result column="parent_id" property="parentIdentifier" jdbcType="INTEGER"/>
<result column="type" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.ConnectionGroup$Type"/>
<result column="max_connections" property="maxConnections" jdbcType="INTEGER"/>
<result column="max_connections_per_user" property="maxConnectionsPerUser" jdbcType="INTEGER"/>
<result column="enable_session_affinity" property="sessionAffinityEnabled" jdbcType="BOOLEAN"/>
<!-- Child connection groups -->
<collection property="connectionGroupIdentifiers" resultSet="childConnectionGroups" ofType="java.lang.String"
column="connection_group_id" foreignColumn="parent_id">
<result column="connection_group_id"/>
</collection>
<!-- Child connections -->
<collection property="connectionIdentifiers" resultSet="childConnections" ofType="java.lang.String"
column="connection_group_id" foreignColumn="parent_id">
<result column="connection_id"/>
</collection>
</resultMap>
David,
I know this is a little old, but I'm also trying to implement a SQLite JDBC module, and ran into exactly the same problem. I've managed to track down the source of the issue, and have filed an issue on the JDBC SQLite github page:
https://github.com/xerial/sqlite-jdbc/issues/277
Basically, the SQLite JDBC driver computes one of its array sizes based on the parameter count for a prepared statement. However, in the cases you mentioned, there are multiple SELECT statements which take the same parameters, so the array needs to be x * y (x = parameter count, y = number of select statements) rather than just the number of parameters. When it tries to prepare the statement, it hits the first position beyond the parameter count and generates this exception.
The other JDBC modules - MySQL, PostgreSQL, and SQL Server, as well as Oracle and H2 that I'm messing with - seem to handle this situation correctly (well, Oracle is a little...special...), but the SQLite driver does not.
I was able to work around the issue in a really, really kludgy way, by creating two different result maps, one for the generic select and one for the read that checks for READ permissions, and then break out each of the select queries into its own SELECT block and call those from the collection inside the result map. It's nowhere near as elegant as the existing code, but it works.

I am trying to fetch data kept in a table's column with datatype <XMLTYPE>. I have to get all field names with values using procedure/ query

<record>
<field>
<fieldName>employee id</fieldName>
<fieldValue>2000001</fieldValue>
</field>
<field>
<fieldName>employee name</fieldName>
<fieldValue>pankaj kumar</fieldValue>
</field>
</record>
The data extracted should be like this:
employee id | employee name
2000001 | pankaj kumar
CREATE TABLE houses(
HOUSE_ID NUMBER(4),
house_add XMLTYPE,
HOUSE_NAME VARCHAR2(35)
);
Inserting the value in the table;
INSERT INTO houses VALUES
(100, XMLType('<house whNo="100">
<Building>Owned</Building>
</house>'), 'housename1');
To fech :-
SELECT house_add FROM HOUSES W;
o/p:-<house whNo="100"> <BUILDING>OWNED</BUILDING> </house>
To fetch Building detail:-
SELECT
w.house_add.extract('/house/Building/text()').getStringVal() "Building"
FROM HOUSES W;
o/p:-Owned
For your case:-
WITH T AS
(select xmltype('<?xml version = "1.0"?>
<record>
<FIELD>
<Field Name="employee id" fieldValue="2000001"/>
</FIELD>
<FIELD>
<Field Name="employee name" fieldValue="pankajkumar"/>
</FIELD>
</record>
') XML FROM DUAL
)
SELECT Y.NAME, Y.VALUE
FROM T ,
XMLTABLE('/record/FIELD/Field'
PASSING T.XML
COLUMNS NAME VARCHAR2(20) PATH '#Name',
VALUE VARCHAR2(20) PATH '#fieldValue'
)Y
output:-
NAme Value
employee id 2000001
employee name pankajkumar
This will help you !!

Mondrian parent-child hierarchy not working

Some issues to make mondrian work with a parent-child hierarchy.
My table structure is as follows (simplified, as the Category table is actually a MPTT):
RESPONSE QUESTION CATEGORY
-------------- ------------------- ----------
id ¡---> identifier (String) ¡---> id <---¡
question_id ___| category_id _____| parent_id _|
value (Measure) title name_en
My closure table is a simple setup: child_id, parent_id, distance (with the primary key being the tuple (child_id, parent_id) ).
My cube's schema is as follows:
<Cube cache="true"
defaultMeasure="Value" enabled="true" name="mycube">
<Table name="response" schema="public"/>
<Dimension foreignKey="question_id" name="Category">
<Hierarchy allMemberName="All Categories" hasAll="true"
primaryKey="identifier" primaryKeyTable="question">
<Join leftKey="category_id" rightKey="id">
<Table name="question"/>
<Table name="category"/>
</Join>
<!-- works fine with the category itself: <Level column="name" type="String" name="Category Name" table="category" uniqueMembers="true"/> -->
<Level column="id" name="Category ID"
nameColumn="name_en" nullParentValue="NULL"
parentColumn="parent_id" table="category"
type="Numeric" uniqueMembers="true">
<!-- type="Numeric" ordinalColumn="lft" parentColumn="parent_id" nullParentValue="NULL" -->
<Closure childColumn="child_id" parentColumn="parent_id">
<Table name="category_closure"/>
</Closure>
</Level>
</Hierarchy>
</Dimension>
<Measure aggregator="avg" caption="Value"
column="actual_value" formatString="#,###.00" name="Value"/>
</Cube>
Now, based on the mondrian FoodMart test pages, I have set up a simple jsp pages for my cube, which I want to use as a starting point for my tests. It has the following MDX:
select {[Measures].[Value]} ON COLUMNS,
{( [Category] )} ON ROWS
from [mycube]
The result it shows at first is "All Categories". When I try to drill down or hierarchize in the Categories, it returns nothing but [All Categories]. I have tried also with Descendants() to no avail.
Equally, when I try to list the members of Categories, it returns nothing.
I see that in the background it runs a query as follows to start the drilling down:
05/12/13 23:53:10,967 postgres: [3-1] LOG: execute : select
"category"."id" as "c0", "category"."name_en" as "c1" from "question"
as "question", "category" as "category" where "question"."category_id"
= "category"."id" and "category"."parent_id" IS NULL group by "category"."id", "category"."name_en" order by "category"."id" ASC
NULLS LAST
Obviously this query has an empty result because it joins question with root-level categories whilst only the leaves of my tree are attached some Questions.
It also shows that the closure table is not used here.
Any clue on what I can do to fix this?
Thanks ahead
lai
Following a few experiments, I shall conclude that my use case is probably not supported by Mondrian.
Here is the test I did to come to this conclusion:
- ensure I have 3 levels in my tree (level 0->2)
- create a fake question related to a root category (i.e. whose parent_id = NULL)
- create a response attached to this fake question
- at this stage, only level 0 and level 2 Category records have questions and responses related to them
- go ahead with a query
Here is the result I got in the logs:
14:37:09,082 WARN [SqlTupleReader] The level [Category].[Name] makes
use of the 'parentColumn' attribute, but a parent member for key 3 is
missing. This can be due to the usage of the NativizeSet MDX function
with a list of members form a parent-child hierarchy that doesn't
include all parent members in its definition. Using NativizeSet with a
parent-child hierarchy requires the parent members to be included in
the set, or the hierarchy cannot be properly built natively.
"key 3" relates to one of my level-2 records i.e. tree leaves (similar messages show for the other level-2 records).
Conclusion: not supported :-(
Enclosing the "working" schema below:
<Schema name="Foo">
<Cube name="Foo" caption="Cube to report on the Foo quizz dimensions" visible="true" defaultMeasure="Rating" cache="true" enabled="true">
<Table name="response" schema="public">
</Table>
<Dimension type="StandardDimension" visible="true" foreignKey="question_id" highCardinality="false" name="Category">
<Hierarchy name="Category" visible="true" hasAll="false" allMemberName="All Categories" primaryKey="identifier" primaryKeyTable="question">
<Join leftKey="category_id" rightKey="id">
<Table name="question" schema="public">
</Table>
<Table name="category" schema="public">
</Table>
</Join>
<Level name="Name" visible="true" table="category" column="id" nameColumn="name" ordinalColumn="tree_id" parentColumn="parent_id" nullParentValue="NULL" type="String" uniqueMembers="true" levelType="Regular" hideMemberIf="Never">
</Level>
</Hierarchy>
</Dimension>
<Measure name="Ratings" column="actual_value" formatString="#,###.00" aggregator="avg" caption="Ratings">
</Measure>
</Cube>
</Schema>

Query to output content of AllXml column of ELMAH_Error sql server table

I am having trouble writing query so that I can query the content of AllXml column inside Elmah_Error table.
How can I list out all the item nodes as an output of the query.
How could I write query to only list for certain item nodes?
I would like to get follow resultset:
item value
===== =====
ALL_HTTP HTTP_CONNECTION:xxxx
ALL_RAW Connection: xxxxx
I would also like to be able to filter the query by ErrorID
Content of AllXml column may look like this.
<error
application="/"
message="hello world"
source="TestWebElmah"
detail="xxxxx">
<serverVariables>
<item
name="ALL_HTTP">
<value
string="HTTP_CONNECTION:xxxx" />
</item>
<item
name="ALL_RAW">
<value
string="Connection: xxxxx" />
</item>
</serverVariables>
</error>
Remote Addr nodes
select T.N.value('(value/#string)[1]', 'varchar(30)') as REMOTE_ADDR
from
(select cast(AllXml as xml) as AllXml from ELMAH_Error) e
cross apply AllXml.nodes('//item[#name="REMOTE_ADDR"]') as T(N)
HTTP User Agents which contain mozilla
select T.N.value('(value/#string)[1]', 'varchar(30)') as HTTP_USER_AGENT
from
(select cast(AllXml as xml) as AllXml from ELMAH_Error) e
cross apply AllXml.nodes('//item[#name="HTTP_USER_AGENT"]') as T(N)
where T.N.value('(value/#string)[1]', 'varchar(30)') like '%mozilla%'
Elmah table stores the AllXml column as nvarchar so it needs to be casted to xml
all tags + values, by error id
select T.N.value('#name', 'varchar(30)') as Name,
T.N.value('(value/#string)[1]', 'varchar(30)') as Value
from
(select cast(AllXml as xml) as AllXml from ELMAH_Error where ErrorId = 'DC82172B-F2C0-48CE-8621-A60B702ECF93') e
cross apply AllXml.nodes('/error/serverVariables/item') as T(N)
Before voting down this answer, because uses most of the part of Mikael Eriksson's answer, I let you know I'll happily accept the downvotes only for this reason, since is mainly true
This query will give you all item nodes
select T.N.value('#name', 'varchar(30)') as Name,
T.N.value('(value/#string)[1]', 'varchar(30)') as Value
from Elmah_Error
cross apply AllXml.nodes('/error/serverVariables/item') as T(N)
If you want to filter on any of the values you can put that in a sub-query apply a regular where clause.
select Name,
Value
from
(
select T.N.value('#name', 'varchar(30)') as Name,
T.N.value('(value/#string)[1]', 'varchar(30)') as Value
from Elmah_Error
cross apply AllXml.nodes('/error/serverVariables/item') as T(N)
) T
where Name = 'ALL_HTTP'

Accessing child nodes in SQLXML columns with XQuery

I have a database which has a table with an XML column. The XML data has a bunch of child nodes which look something like this:
<test>
<result id="1234">
<data elementname="Message">some error message</data>
<data elementname="Cat">Cat01</data>
<data elementname="Type">WARNING</data>
</result>
<result id="5678">
<data elementname="Message">some error message</data>
<data elementname="Cat">Cat01</data>
<data elementname="Type">WARNING</data>
</result>
</test>
The Cat element can have a number of different values. I'm trying to create reports on this data, so one thing I'd like to do is get a list of all the categories througout our data. This is my query:
Select Id, XmlData.query('/test/result/data[#elementname = ''Cat''] ') AS Message
From Table
WHERE XmlData.exist('/test/result/data[#elementname = ''Cat'']') = 1
ORDER BY FriendlyName
This correctly gets all the rows in my table with this type of categorization (there'll be other results in the same table without that element), but the categories are all combined into one column for each table record:
Id1, <data elementname="Cat">Cat01</data><data elementname="Cat">Cat01</data>
Id2, <data elementname="Cat">Cat01</data><data elementname="Cat">Cat01</data>
I'm including the Id column so it's easy to see where the data is coming from, the main problem is that I can only get it to concatenate the values for each row - I need each of those data elements to have its own row, then maybe do a Select Distinct on the result.
Is there a way I can do that?
Thanks
Always the Google after you post your question....
Think I found the answer here: http://blogs.msdn.com/b/simonince/archive/2009/04/24/flattening-xml-data-in-sql-server.aspx
SELECT DISTINCT cref.value('(text())[1]', 'varchar(50)') as Cat
FROM
SGIS CROSS APPLY
Data.nodes('/test/result') AS Results(rref) CROSS APPLY
rref.nodes('data[#elementname = ''Cat'']') AS Categories(cref)
Seems the key is the Cross Apply keywords

Resources