robinlu / mybatisnet

Automatically exported from code.google.com/p/mybatisnet
0 stars 0 forks source link

Support for inclusion of <result> fragments into <resultMap> elements #6

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What version of the MyBatis.NET are you using?
IBatis.DataMapper.1.6.2

Please describe the problem.  Unit tests are best!
This is an enhancement request. I would like iBATIS to support <include/> kind 
of functionality for the <resultMap/> and <parameterMap/> elements -- Something 
similar to what iBATIS already provides for <statement/> tags family via <sql/> 
and <include/> tags.

What is the expected output? What do you see instead?

Please provide any additional information below.
There are use cases where I have to map the results of different SELECT queries 
into objects which do not form any inheritance hierarchy, though these objects 
do share some properties (and unfortunately, their inheritance line cannot be 
changed), and this leads to a lot of repetition of <result/> elements in 
different <resultMap/>s. If I could have a feature similar to <sql/> and 
<include/> working for result/parameter maps as well, then it will really help 
in keeping the XML concise.

Original issue reported on code.google.com by sodhi.b@gmail.com on 7 Aug 2010 at 2:34

GoogleCodeExporter commented 9 years ago
You can extend one <resultMap> with another, just like you can Inherit from 
another object in code.

<resultMap id="BaseClassMap" class="YourClass">
    <result property="ID" column="ID" />
    <result property="Name" column="Name" />
</resultMap>

<resultMap id="ExtendedClassMap" class="YourClass2" extends="BaseClassMap">
    <result property="PhoneNumber" column="PhoneNumber" />
</result>

I do this all the time and there is normally very little to no repetition of 
<result> objects.

Original comment by consultc...@gmail.com on 31 Aug 2010 at 6:47

GoogleCodeExporter commented 9 years ago
@consultcory: Your solution requires that the mapped classes should form an 
inheritance hierarchy. As I mentioned in the description, it is not always 
possible to put the mapped objects into a hierarchy. 

Original comment by sodhi.b@gmail.com on 1 Sep 2010 at 1:15

GoogleCodeExporter commented 9 years ago
It's not necessarily true that the mapped classes are required to be part of an 
inheritance hierarchy. Sometimes I'll have a result map (a) that only sets some 
of the properties of an object, where another result map (b) that extends (a) 
sets more properties depending on the result of the query. Both (a) and (b) map 
to the same class.

I don't think your situation is typical. Are you trying to map to classes that 
you can't modify or don't have control over?

Original comment by consultc...@gmail.com on 1 Sep 2010 at 6:44

GoogleCodeExporter commented 9 years ago
Lets say I have a class hierarchy that is similar to the one below:

ProductDetails
-productId
-name
-foo
-bar

ProductSearchInput : ProductDetails
-stockCode
-units

ProductSearchResultItem : ProductSearchInput
-serialNum
-storeId

This hierarchy cannot be changed due to various reasons. Now, we have different 
queries whose results (which have different columns for each query) need to be 
mapped to different classes from the above hierarchy. In such a situation, the 
resultMap extension mechanism won't work as you suggest. 

A feature similar to the <sql/> and <include/> would work well in such a case.

Original comment by sodhi.b@gmail.com on 2 Sep 2010 at 2:49

GoogleCodeExporter commented 9 years ago
I guess I don't entirely understand the need for what you're asking. In your 
case I would have the following SQL map:

<sqlMap namespace="Product">

    <alias>
        <typeAlias alias="ProductDetails" type="Company.Project.Domain.ProductDetails" />
        <typeAlias alias="ProductSearchInput" type="Company.Project.Domain.ProductSearchInput" />
        <typeAlias alias="ProductSearchResultItem" type="Company.Project.Domain.ProductSearchResultItem" />
    </alias>

    <resultMaps>

        <resultMap id="ProductDetails" class="ProductDetails">
            <result property="productId" column="ProductId" />
            <result property="name" column="Name" />
            <result property="foo" column="Foo" />
            <result property="bar" column="Bar" />
        </resultMap>

        <resultMap id="ProductSearchInput" class="ProductSearchInput" extends="Product.ProductDetails">
            <result property="stockCode" column="StockCode" />
            <result property="units" column="Units" />
        </resultMap>

        <resultMap id="ProductSearchResultItem" class="ProductSearchResultItem" extends="Product.ProductSearchInput">
            <result property="serialNum" column="SerialNum" />
            <result property="storeId" column="StoreId" />
        </resultMap>

        </resultMaps>

    <statements>

        <select id="SelectProductDetails" parameterClass="int" resultMap="ProductDetails">
            <!-- Query that returns columns or column aliases "ProductId," "Name," "Foo," and "Bar." -->
        </select>

        <select id="SelectProductSearchInput" parameterClass="ProductDetails" resultMap="SelectProductSearchInput">
            ...
        </select>

        <select id="SelectProductSearchResultItem" parameterClass="ProductSearchInput" resultMap="ProductSearchResultItem">
            ...
        </select>

    </statements>

</sqlMap>

The ProductSearchInput result map, when extending the Product.ProductDetails 
result map, will allow you to map to the four fields from the ProductDetails 
map and the two from the ProductSearchInput map, just as your 
ProductSearchInput class has access to the four fields from ProductDetails.

Likewise with the third result map. The ProductSearchResultItem will actually 
have all eight fields available to map to, not just the two you see in the map, 
because it extends the ProductSearchInput map which extends the ProductDetails 
map.

I didn't have to repeat any result properties anywhere in the SQL map. Maybe 
some sample queries would help clear things up for me, or maybe I'm just way 
off the path here. Help me help you :)

Original comment by consultc...@gmail.com on 2 Sep 2010 at 7:58

GoogleCodeExporter commented 9 years ago
Thanks consultcory! What you mentioned works well (and such I have used) for 
situations where queries don't change much. Consider the following queries:

<select id="FindDetails" parameterClass="string" resultMap="ProductDetails">
 SELECT prod_id, name, foo, bar FROM products WHERE name LIKE '%CPU%'
</select>

<select id="Search2" parameterClass="ProductSearchInput" 
resultMap="ProductSearchResultItem">
  SELECT p.*, s.* FROM products p, store_items s WHERE p.prod_id=s.prod_id
  <dynamic prepend='AND'>
   <!-- Dynamic conditions go here -->
  </dynamic>
</select>

Now, if I need to add (select) an additional property/column to ProductDetails 
(i.e. the query "FindDetails"), then all my queries where I use result maps 
deriving from the one used in "FindDetails" would break, unless I select the 
additional columns in all those "child queries" as well. Having something like 
<sql/>, <include/> would provide a cleaner solution to "refactor" the result 
maps, because it would allow the reuse of <result/> fragments without the need 
of inheritance of <resultMap/> and the mapped classes. I hope this clarifies 
the situation better.

Original comment by sodhi.b@gmail.com on 3 Sep 2010 at 4:15