How Mybatis returns a map with a key instead of a null - mybatis

Mybatis set resultType is map,when result is null how to return Map containing key Map rather than null
<setting name="callSettersOnNulls" value="true" /> The setting is not used, return null

Related

Spring MyBatis pass default value if null or empty

Is there a way to pass a default value (zero) to MyBatis #Insert(<script>… … testVal … values … #{TESTVAL} … …) query using #Results({ #Result(property=“testVal”, column=“TESTVAL”, value=“${testVal:0}”, jdbcType.INTEGER), … …}) ? Or something similar?

How to iterate List in MyBatis

iBatis to MyBatis Migration:
Need Help for MyBatis foreach logic, because the Map contains Value as ArrayList.
The below java code is the logic:
employeeRequest.put("ID", employeeId);
Map <String,ArrayList<String> employeeRequest = new HashMap<String, ArrayList<String>>();
Set<String> employeeSet = new HashSet<String>();
for(Employee employee: employeeList) {
String name = employee.getName();
String value = employee.getValue();
if("EMPLOYEE".equalsIgnoreCase(name) {
employeeSet.add(value)
}
}
if(!employeeSet.isEmpty()) {
employeeRequest.put("EMPLOYEE", new ArrayList<String>(employeeSet))
}
iBatis SQL:
My Previous code I am using iBatis which has the following query
<select id="getEmployeeName" resultclass="java.util.HashMap" parameterClass="java.util.Map">
SELECT EMP.EMPNAM NAME FROM EMPLOYEE EMP
WHERE EMP.ID = #ID#
<isNotEmpty property="EMPLOYEE" prepend="AND">
<iterate property="EMPLOYEE" conjunction="AND">
EMP.EMPNAM != #EMPLOYEE[]#
<iterate>
</isNotEmpty>
</select>
MyBatis SQL:
Now I am migrating to MyBatis, so formatted the query as below
<select id="getEmployeeName" resultclass="java.util.HashMap" parameterClass="java.util.Map">
SELECT EMP.EMPNAM NAME FROM EMPLOYEE EMP
WHERE EMP.ID = #{ID}#
<if test="EMPLOYEE !=null and EMPLOYEE>0">
<foreach collection="EMPLOYEE" index="index" item="item" separator="AND">
EMP.EMP_ID != ${item}
</foreach>
</if>
</select>
Could any one of you please help me with the correct query for the above java code logic.
Missing spaces around separator value: AND instead of just AND.
For parameters use #{param} to bind parameter instead of ${param} that just concatenates values to the SQL string. That does not prevent from working but that is very bad.
!= is not standard SQL and will not work for every DB vendor (although it might do with the one you are using), unlike NOT column = value,
<foreach collection="EMPLOYEE" index="index" item="item" separator=" AND ">
NOT EMP.EMP_ID = #{item}
</foreach>
furthermore better use IN:
EMP.EMP_ID NOT IN (<foreach collection="EMPLOYEE" index="index" item="item" separator=", ">
#{item}
</foreach>)

How set foreign key to null when entity keys are of type bigint (ulong)?

In my model I'm using bigint (ulong) as the type for entity keys. I want the database to enforce referential integrity, so I have set persistenceEnforce to true. Columns for foreign keys are nullable. With referential integrity an entity can only be deleted if no foreign key is referring to the entity, so before deleting an entity I must first set each foreign key for this associated entity to null. However, I don't know how to clear the foreign key.
Here is my model:
<cf:entity name="Order" cfom:bindingList="false">
<cf:property name="Id" typeName="ulong" key="true" persistenceIdentity="true" cfps:hint="CLUSTERED" />
<cf:property name="Invoice" typeName="Invoice" persistenceEnforce="true" />
</cf:entity>
<cf:entity name="Invoice" cfom:bindingList="false">
<cf:property name="Id" typeName="ulong" key="true" persistenceIdentity="true" cfps:hint="CLUSTERED" />
<cf:property name="Name" typeName="string" />
</cf:entity>
Here is my code:
Invoice invoice = new Invoice();
invoice.Save();
Order order = new Order();
order.Invoice = invoice;
order.Save();
// We must clear the reference to the invoice before deleting the invoice,
// because the database enforces referential integrity.
order.InvoiceId = 0;
order.Save();
invoice.Delete();
The above code throws the following exception when saving the order for the second time:
The UPDATE statement conflicted with the FOREIGN KEY constraint \"FK_Ord_Ore_Inv_Inv\".
This is because the code produced by CodeFluent inserts the value 0 instead of null into the "Order_Invoice_Id" column. The following line in the Order.BaseSave method seems to be wrong:
persistence.AddParameter("#Order_Invoice_Id", this.InvoiceId, ((ulong)(0ul)));
I tried the settings persistenceDefaultValue="null" and usePersistenceDefaultValue="true" on the Invoice propery, but that did not solve the problem.
Note: A property of type UInt64 (unsigned) is translated to a column of type bigint (signed). So be careful with the conversions... FYI CodeFluent Entities uses CodeFluent.Runtime.Utilities.ConvertUtilities to convert values.
The overload AddParameter(string name, ulong value, ulong defaultValue) doesn't use the default value, so it does not translate the default value to NULL. As a workaround, you can create a PersistenceHook that changes the value of the parameter to match the expected behavior:
public class CustomPersistenceHook : BasePersistenceHook
{
public override void AfterAddParameter(string name, object value, IDbDataParameter parameter)
{
if (value is ulong && name == "#Order_Invoice_Id")
{
var defaultValue = (ulong)ContextData["defaultValue"];
if (defaultValue == (ulong)value)
{
parameter.Value = DBNull.Value;
}
}
base.AfterAddParameter(name, value, parameter);
}
}
Then, you need to register the persistence hook:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Sample" type="CodeFluent.Runtime.CodeFluentConfigurationSectionHandler, CodeFluent.Runtime" />
</configSections>
<Sample persistenceHookTypeName="Sample.CustomPersistenceHook, Sample" />
</configuration>

Composite keys in MyBatis <collection> mappings

I am unable to pass a composite key to a MyBatis <collection> element (using version 3.2.7). The MyBatis documentation states:
Note: To deal with composite keys, you can specify multiple column names to pass to the nested select statement by using the syntax column="{prop1=col1,prop2=col2}". This will cause prop1 and prop2 to be set against the parameter object for the target nested select statement.
However, all my attempts to implement this produce the Exception
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Error instantiating class java.lang.Integer with invalid types () or values (). Cause: java.lang.NoSuchMethodException: java.lang.Integer.<init>()
The collection (which resides in another ResultsMap) is:
<collection property="foos" ofType="FooObject"
column="{param1=user_id,param2=foo_id}" select="getFoosByUser" >
<id property="userId" column="user_id" />
<id property="foo" column="foo_id" />
<result property="fooName" column="foo_name" />
</collection>
It should return an ArrayList of Foo objects. The composite key is user_id and foo_id. The select query is:
<select id="getFoosByUser" parameterType="Integer" resultType="FooObject">
SELECT
user_id AS userId,
foo_id AS fooId,
foo_name AS fooName
FROM foo_table
WHERE user_id = #{param1}
AND foo_id = #{param2}
</select>
The query works correctly if I only use one parameter, e.g. removed foo_id=#{param2} and then use column=user_id in the collection, but I cannot work out how to structure the column attribute correctly for two keys. Any ideas?
MyBatis is confused by using parameterType when there are more than one parameter. Modify you query mapping like this:
<select id="getFoosByUser" resultType="FooObject">
SELECT
user_id AS userId,
foo_id AS fooId,
foo_name AS fooName
FROM foo_table
WHERE user_id = #{param1}
AND foo_id = #{param2}
</select>

Change Primary Key of .edmx

I have a .edmx file generated from a database having table "table1".
table1 has following attributes.
ID: Int (Primary Key)
Name: String
Tag: String
Description: String
In my edmx file, I want to change primary key from ID to (Name, Tag). How can I do that?
In the .edmx file, CSDL section, look for a tag for the element you want to change:
<edmx:ConceptualModels>
<Schema Namespace="DatabaseFirst.BloggingModel" ... >
<EntityType Name="Blog">
<Key>
<PropertyRef Name="BlogId" />
</Key>
<Property Name="BlogId" Type="InT32" ... />
Change the Name attribute in the PropertyRef and Property tags to your new desired primary key name.