Inheritance with MyBatis and XML - java

So I got MyBatis inheritance working with annotations - child inherited #Select functionality.
But with XML files it's not working accordingly.
It will throw:
org.apache.ibatis.binding.BindingException: Invalid bound statement /.../
Saw that some used extends on the mapper element, but for me it says "Attribute extends not allowed here"
Tried <cache/> on parent and <cache-ref namespace="parent"/> on child but that threw org.apache.ibatis.builder.IncompleteElementException: No cache for namespace 'parent'
So how to get MyBatis inheritance working with XML configuration?

Attribute extends applies to resultMap only.
cache and cache-ref are about cache management.
All what may look like extending is actually factorizing: define sql fragments in a XML mapper and reference them in other mappers. E.g:
-Mapper1.xml:
<sql id="a">/* dummy will never actually been included */</sql>
<sql id="b"> something common to include </sql>
<sql id="template">
<include refid="a" />
<include refid="Mapper1.b" />
</sql>
-Mapper2.xml
<sql id="a"> something specific to this mapper </sql>
<select id="statement">
<include refid="Mapper1.template" />
</select>
include tag behaves just like copy/paste of referenced fragments.
Then the select statement will yield:
something specific to this mapper
something common to include
The trick is to play with prefixing or not referenced fragments. It may look like overriding.

I agree whit balckwizzard cache and cache-ref are not useful in this case (I have read too somewhere a post that suggest to use they to extend xml but I think that the post war an error)
I have put an answer that I think is good for you too:
Mybatis Generator: What's the best way to separate out “auto generated” and “hand edited files”
regards

Related

XML parsing to Java Object List<Map<String,String>> sqlParams;

In one of my projects i have a scenario where I'll be getting a xml file which contain sql parametrs, I have to read and construct Java object from that.
Below is sample xml
<parameters>
<sql id="1">
<city>Chennai</city>
<state>Tamilnadu</state>
</sql>
<sql id="2">
<city>Mumbai</city>
<state>Maharashtra</state>
</sql>
<sql id="3">
<city>Kolkata</city>
<state>West Bengal</state>
</sql>
</parameters>
I have to parse and get keys and values from these xml.
The Java object I'm expecting is
List<Map<String,String>> sqlParams;
Map sqlOne; sqlOne.put(city,Chennai); sqlOne.put(state,Tamilnadu); sqlParams.add(sqlOne);
Map sqlTwo; sqlTwo.put(city,Mumbai); sqlTwo.put(state,Maharashtra); sqlParams.add(sqlTwo);
and so on...
We use this List of map to run SQL.
Can some one suggest me a better way to do this.
To parse xml in java object, you can look into this documentation. http://docs.oracle.com/javase/8/docs/technotes/guides/xml/index.html
a very fast and convenient way of mapping XML is to use some existing library like Jackson.
It's usage is quite simple. You write a plain object class like the example:
public class Simple {
public int x = 1;
public int y = 2;
}
which maps a structure like this:
<Simple>
<x>1</x>
<y>2</y>
</Simple>
After installing the library you it's intuitive how to map your data structure.
I would recommend for your next projects to use a some project management tools (like maven or gradle) which allows you to easily import libraries for such tasks and to spend some time to investigate how database querying is implemented around. You might have a look to spring JPA just as a starting point.

How would I map an #Entity with a hbm.xml?

I in a situation where I need to override some fields in a #Entity class but I can't edit the class. It just so happens that this #Entity class is mapped in a way that I don't think it's possible to partially override it. I was wondering what would be the steps to overriding this class completely or maybe partially if possible.
The class:
org.broadleafcommerce.profile.core.domain.AddressImpl
I've used a hbm.xml and a orm.xml but I'm not exactly sure how to configure them properly.
The book Pro JPA 2 : Mastering the Java Persistence API notes:
The metadata-complete attribute is an attribute on the entity,
mapped-superclass, and embeddable elements. If specified, all
annotations on the specified class and on any fields or properties in
the class will be ignored, and only the metadata in the mapping file
will be considered as the set of metadata for the class. When
metadata-complete is enabled, the same rules that we applied to
annotated entities will still apply when using XML-mapped entities.
For example, the identifier must be mapped, and all relationships must
be specified with their corresponding cardinality mappings inside the
entity element.
So you will need an entry in your orm.xml like the below, adding all other persistent attributes as required (partial override is not possible).
<entity-mappings>
<entity class="com.Foo" metadata-complete="true">
<table name="FOO"/>
<attributes>
<id name="id"/>
</attributes>
</entity>
</entity-mappings>

MyBatis Generator single resultMap

Im using MyBatis Generator to generate JavaBean and Mapper.xml.
But the Mapper.xml is different as I expected .
Mapper.xml contain two resultMap, BaseResultMap and ResultMapWithBLOBs.
I only want one resultMap contain all column.
Tough to know how you have your mybatis generator configuration set up, but the way to do this is through configuring the context's Model Type.
MBG provides an enum called ModelType which allows you to control how the Java Model classes (your beans) are generated. You want to use ModelType.FLAT in your context configuration to avoid any extra bean classes being created.
One option to avoid the creation of "WithBlobs" subclasses is to specify <columnOverride/> to use non-Blob jdbc types in your generator config for the Blob columns.
So, in the example of a TEXT column named "bar" in your table, you can specify VARCHAR instead:
<table tableName='foo' domainObjectName='Foo'>
<property name='useActualColumnNames' value='true' />
<columnOverride column="bar" property="bar" jdbcType="VARCHAR" />
</table>

Hibernate use same mapping for multiple tables

I have 2 identical DB instances containing FOO_TABLE with the same schema. So, currently I have one class definition per DB instance:
<class name="FooTable" table="FOO_TABLE" entity-name="FooTableInstance1">
<property name="..." column="..." />
<property name="..." column="..." />
....
</class>
<class name="FooTable" table="FOO_TABLE" entity-name="FooTableInstance2">
<property name="..." column="..." />
<property name="..." column="..." />
....
</class>
The problem is that I don't want to copy-paste the properties, as the tables have the same schema. Is it possible to inherit the 2 classes from a base class which contains all the mappings and in the 2 children classes specify different entity-name?
An alternative (and perhaps the correct one if I understand your question correctly) is to use a #MappedSuperclass to define the common mappings. Whether you use this or the suggestion posted previously depends on the data model: for example are these two entities related so that you would like to be able to query across both of them?
e.g. select f from Foo returns all Foo1 and Foo2.
This cannot be done when Foo is a MappedSuperclass.
See here for further details:
http://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Mapped_Superclasses
JPA: Implementing Model Hierarchy - #MappedSuperclass vs. #Inheritance
Yes, it is possible. Take a look at the relevant documentation: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html
More specifically, check 9.1.5. Table per concrete class. Make the parent class abstract and things should work fine.
According to the documentation you need 3 Java classes:
Foo (abstract, containing all fields you want in both tables)
FooChild1 (concrete, subclass of Foo, containing no new fields)
FooChild2 (concrete, subclass of Foo, containing no new fields)
You will need two tables. One mapping to FooChild1, and another to FooChild2.

How to express a Serializable Blob type in a hibernate mapping file

I have a legacy application that uses hibernate for mapping objects into a database. It uses the Hibernate Mapping XML file to do so. The java class contains two properties abc and def that implement java Serializable. The mapping is defined this way:
<property name="abc" column="ABC" type="serializable" length="32672"/>
<property name="def" column="DEF" type="serializable" length="32672"/>
When I try to set this up with oracle, I get a nasty error "ORA-01754: a table may contain only one column of type LONG" which essentially is complaining about creating two 'long raw' columns in one table. Oracle does not like this. After reading up on the issue, the recommended approach is to use blobs instead of 'long raw' types.
My question is, how can I express in the hibernate mapping file to use a serializable type mapped into a blob column? I would think there would be a serializable_blob type but there does not seem to be.
I know this is possible with JPA annotations using #Basic and #Lob. It should also be possible using the hibernate mapping file. How can this be done in the hibernate mapping file?
Update:
The following do not work as Serializable works:
type=binary - This one expects a byte[]. Does not work for Serializable classes. Gives ClassCastException.
type=blob - - This one expects a java.sql.Blob. Does not work for Serializable classes. Gives ClassCastException.
type=materialized_blob - - This one expects a byte[]. Does not work for Serializable classes. Gives ClassCastException.
<property
name="data"
type="blob"
column="DATA"/>
...
should work.
Ok, did some more research following my comment above and, by Jove, I found it.
In Hibernate 3.5 + Spring 3.1, I used Spring's org.springframework.orm.hibernate3.support.BlobSerializableType. Now I'm upgrading to Hibernate 4.3, that option isn't available anymore. I did find the type to column mappings as OP, but in my application there are various Strings (legacy) that are mapped to BLOB fields.
So, as I reported in the comment above, I found the org.hibernate.type.SerializableToBlob type, which is parameterize. Below how I got the mapping to work (using good old-fashioned hbm.xml mappings)
<property name="description" column="TEXT">
<type name="org.hibernate.type.SerializableToBlobType">
<param name="classname">java.lang.String</param>
</type>
</property>
And that appears to do the trick. (the classname value should be the type of the attribute you are mapping, I think)

Categories

Resources